reflex-agent 0.2.1

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 (365) hide show
  1. package/.next/BUILD_ID +1 -0
  2. package/.next/app-build-manifest.json +319 -0
  3. package/.next/app-path-routes-manifest.json +34 -0
  4. package/.next/build-manifest.json +33 -0
  5. package/.next/diagnostics/build-diagnostics.json +6 -0
  6. package/.next/diagnostics/framework.json +1 -0
  7. package/.next/export-marker.json +6 -0
  8. package/.next/images-manifest.json +58 -0
  9. package/.next/next-minimal-server.js.nft.json +1 -0
  10. package/.next/next-server.js.nft.json +1 -0
  11. package/.next/package.json +1 -0
  12. package/.next/prerender-manifest.json +160 -0
  13. package/.next/react-loadable-manifest.json +8 -0
  14. package/.next/required-server-files.json +337 -0
  15. package/.next/routes-manifest.json +282 -0
  16. package/.next/server/app/_not-found/page.js +2 -0
  17. package/.next/server/app/_not-found/page.js.nft.json +1 -0
  18. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
  19. package/.next/server/app/_not-found.html +1 -0
  20. package/.next/server/app/_not-found.meta +8 -0
  21. package/.next/server/app/_not-found.rsc +18 -0
  22. package/.next/server/app/agents/[agentId]/page.js +3 -0
  23. package/.next/server/app/agents/[agentId]/page.js.nft.json +1 -0
  24. package/.next/server/app/agents/[agentId]/page_client-reference-manifest.js +1 -0
  25. package/.next/server/app/api/agents/[agentId]/respond/route.js +2 -0
  26. package/.next/server/app/api/agents/[agentId]/respond/route.js.nft.json +1 -0
  27. package/.next/server/app/api/agents/[agentId]/respond/route_client-reference-manifest.js +1 -0
  28. package/.next/server/app/api/images/[rootId]/[file]/route.js +1 -0
  29. package/.next/server/app/api/images/[rootId]/[file]/route.js.nft.json +1 -0
  30. package/.next/server/app/api/images/[rootId]/[file]/route_client-reference-manifest.js +1 -0
  31. package/.next/server/app/api/oauth/callback/route.js +22 -0
  32. package/.next/server/app/api/oauth/callback/route.js.nft.json +1 -0
  33. package/.next/server/app/api/oauth/callback/route_client-reference-manifest.js +1 -0
  34. package/.next/server/app/api/oauth/start/route.js +1 -0
  35. package/.next/server/app/api/oauth/start/route.js.nft.json +1 -0
  36. package/.next/server/app/api/oauth/start/route_client-reference-manifest.js +1 -0
  37. package/.next/server/app/api/roots/[id]/attachments/route.js +0 -0
  38. package/.next/server/app/api/roots/[id]/attachments/route.js.nft.json +1 -0
  39. package/.next/server/app/api/roots/[id]/attachments/route_client-reference-manifest.js +1 -0
  40. package/.next/server/app/api/roots/[id]/chat/[topicId]/send/route.js +2 -0
  41. package/.next/server/app/api/roots/[id]/chat/[topicId]/send/route.js.nft.json +1 -0
  42. package/.next/server/app/api/roots/[id]/chat/[topicId]/send/route_client-reference-manifest.js +1 -0
  43. package/.next/server/app/api/roots/[id]/chat/[topicId]/stop/route.js +2 -0
  44. package/.next/server/app/api/roots/[id]/chat/[topicId]/stop/route.js.nft.json +1 -0
  45. package/.next/server/app/api/roots/[id]/chat/[topicId]/stop/route_client-reference-manifest.js +1 -0
  46. package/.next/server/app/api/roots/[id]/chat/[topicId]/stream/route.js +8 -0
  47. package/.next/server/app/api/roots/[id]/chat/[topicId]/stream/route.js.nft.json +1 -0
  48. package/.next/server/app/api/roots/[id]/chat/[topicId]/stream/route_client-reference-manifest.js +1 -0
  49. package/.next/server/app/api/roots/[id]/dashboard/route.js +1 -0
  50. package/.next/server/app/api/roots/[id]/dashboard/route.js.nft.json +1 -0
  51. package/.next/server/app/api/roots/[id]/dashboard/route_client-reference-manifest.js +1 -0
  52. package/.next/server/app/api/roots/[id]/suggestions/route.js +1 -0
  53. package/.next/server/app/api/roots/[id]/suggestions/route.js.nft.json +1 -0
  54. package/.next/server/app/api/roots/[id]/suggestions/route_client-reference-manifest.js +1 -0
  55. package/.next/server/app/api/utilities/[scope]/[id]/bundle.js/route.js +1 -0
  56. package/.next/server/app/api/utilities/[scope]/[id]/bundle.js/route.js.nft.json +1 -0
  57. package/.next/server/app/api/utilities/[scope]/[id]/bundle.js/route_client-reference-manifest.js +1 -0
  58. package/.next/server/app/api/utilities/[scope]/[id]/host/route.js +2 -0
  59. package/.next/server/app/api/utilities/[scope]/[id]/host/route.js.nft.json +1 -0
  60. package/.next/server/app/api/utilities/[scope]/[id]/host/route_client-reference-manifest.js +1 -0
  61. package/.next/server/app/api/utilities/[scope]/[id]/host-api.mjs/route.js +55 -0
  62. package/.next/server/app/api/utilities/[scope]/[id]/host-api.mjs/route.js.nft.json +1 -0
  63. package/.next/server/app/api/utilities/[scope]/[id]/host-api.mjs/route_client-reference-manifest.js +1 -0
  64. package/.next/server/app/api/utilities/[scope]/[id]/host-ui.mjs/route.js +114 -0
  65. package/.next/server/app/api/utilities/[scope]/[id]/host-ui.mjs/route.js.nft.json +1 -0
  66. package/.next/server/app/api/utilities/[scope]/[id]/host-ui.mjs/route_client-reference-manifest.js +1 -0
  67. package/.next/server/app/api/utilities/[scope]/[id]/iframe/route.js +21 -0
  68. package/.next/server/app/api/utilities/[scope]/[id]/iframe/route.js.nft.json +1 -0
  69. package/.next/server/app/api/utilities/[scope]/[id]/iframe/route_client-reference-manifest.js +1 -0
  70. package/.next/server/app/api/utilities/[scope]/[id]/style.css/route.js +1 -0
  71. package/.next/server/app/api/utilities/[scope]/[id]/style.css/route.js.nft.json +1 -0
  72. package/.next/server/app/api/utilities/[scope]/[id]/style.css/route_client-reference-manifest.js +1 -0
  73. package/.next/server/app/audit/page.js +2 -0
  74. package/.next/server/app/audit/page.js.nft.json +1 -0
  75. package/.next/server/app/audit/page_client-reference-manifest.js +1 -0
  76. package/.next/server/app/index.html +1 -0
  77. package/.next/server/app/index.meta +9 -0
  78. package/.next/server/app/index.rsc +19 -0
  79. package/.next/server/app/onboarding/page.js +10 -0
  80. package/.next/server/app/onboarding/page.js.nft.json +1 -0
  81. package/.next/server/app/onboarding/page_client-reference-manifest.js +1 -0
  82. package/.next/server/app/page.js +2 -0
  83. package/.next/server/app/page.js.nft.json +1 -0
  84. package/.next/server/app/page_client-reference-manifest.js +1 -0
  85. package/.next/server/app/roots/[id]/chat/[topicId]/page.js +7 -0
  86. package/.next/server/app/roots/[id]/chat/[topicId]/page.js.nft.json +1 -0
  87. package/.next/server/app/roots/[id]/chat/[topicId]/page_client-reference-manifest.js +1 -0
  88. package/.next/server/app/roots/[id]/kb/[...slug]/page.js +6 -0
  89. package/.next/server/app/roots/[id]/kb/[...slug]/page.js.nft.json +1 -0
  90. package/.next/server/app/roots/[id]/kb/[...slug]/page_client-reference-manifest.js +1 -0
  91. package/.next/server/app/roots/[id]/page.js +5 -0
  92. package/.next/server/app/roots/[id]/page.js.nft.json +1 -0
  93. package/.next/server/app/roots/[id]/page_client-reference-manifest.js +1 -0
  94. package/.next/server/app/roots/[id]/workflows/[wfId]/page.js +2 -0
  95. package/.next/server/app/roots/[id]/workflows/[wfId]/page.js.nft.json +1 -0
  96. package/.next/server/app/roots/[id]/workflows/[wfId]/page_client-reference-manifest.js +1 -0
  97. package/.next/server/app/roots/[id]/workflows/page.js +2 -0
  98. package/.next/server/app/roots/[id]/workflows/page.js.nft.json +1 -0
  99. package/.next/server/app/roots/[id]/workflows/page_client-reference-manifest.js +1 -0
  100. package/.next/server/app/roots/new/page.js +5 -0
  101. package/.next/server/app/roots/new/page.js.nft.json +1 -0
  102. package/.next/server/app/roots/new/page_client-reference-manifest.js +1 -0
  103. package/.next/server/app/roots/new.html +1 -0
  104. package/.next/server/app/roots/new.meta +7 -0
  105. package/.next/server/app/roots/new.rsc +21 -0
  106. package/.next/server/app/settings/page.js +65 -0
  107. package/.next/server/app/settings/page.js.nft.json +1 -0
  108. package/.next/server/app/settings/page_client-reference-manifest.js +1 -0
  109. package/.next/server/app/settings.html +1 -0
  110. package/.next/server/app/settings.meta +7 -0
  111. package/.next/server/app/settings.rsc +22 -0
  112. package/.next/server/app/share/[id]/file/page.js +2 -0
  113. package/.next/server/app/share/[id]/file/page.js.nft.json +1 -0
  114. package/.next/server/app/share/[id]/file/page_client-reference-manifest.js +1 -0
  115. package/.next/server/app/share/[id]/page.js +2 -0
  116. package/.next/server/app/share/[id]/page.js.nft.json +1 -0
  117. package/.next/server/app/share/[id]/page_client-reference-manifest.js +1 -0
  118. package/.next/server/app/utilities/[scope]/[id]/page.js +2 -0
  119. package/.next/server/app/utilities/[scope]/[id]/page.js.nft.json +1 -0
  120. package/.next/server/app/utilities/[scope]/[id]/page_client-reference-manifest.js +1 -0
  121. package/.next/server/app/utilities/page.js +17 -0
  122. package/.next/server/app/utilities/page.js.nft.json +1 -0
  123. package/.next/server/app/utilities/page_client-reference-manifest.js +1 -0
  124. package/.next/server/app-paths-manifest.json +34 -0
  125. package/.next/server/chunks/1088.js +1 -0
  126. package/.next/server/chunks/1105.js +1 -0
  127. package/.next/server/chunks/1223.js +1 -0
  128. package/.next/server/chunks/1244.js +1 -0
  129. package/.next/server/chunks/133.js +490 -0
  130. package/.next/server/chunks/1888.js +1 -0
  131. package/.next/server/chunks/192.js +1 -0
  132. package/.next/server/chunks/1960.js +1 -0
  133. package/.next/server/chunks/1961.js +1 -0
  134. package/.next/server/chunks/1986.js +1 -0
  135. package/.next/server/chunks/2035.js +1 -0
  136. package/.next/server/chunks/2356.js +1 -0
  137. package/.next/server/chunks/2433.js +1 -0
  138. package/.next/server/chunks/2485.js +6 -0
  139. package/.next/server/chunks/2503.js +1 -0
  140. package/.next/server/chunks/3240.js +1 -0
  141. package/.next/server/chunks/3295.js +1 -0
  142. package/.next/server/chunks/3332.js +1 -0
  143. package/.next/server/chunks/3657.js +1 -0
  144. package/.next/server/chunks/4031.js +6 -0
  145. package/.next/server/chunks/4066.js +1 -0
  146. package/.next/server/chunks/4553.js +1 -0
  147. package/.next/server/chunks/4833.js +1 -0
  148. package/.next/server/chunks/4840.js +1 -0
  149. package/.next/server/chunks/4842.js +1 -0
  150. package/.next/server/chunks/4925.js +1 -0
  151. package/.next/server/chunks/5087.js +1 -0
  152. package/.next/server/chunks/5152.js +1 -0
  153. package/.next/server/chunks/5243.js +1 -0
  154. package/.next/server/chunks/5319.js +1 -0
  155. package/.next/server/chunks/5373.js +1 -0
  156. package/.next/server/chunks/5401.js +1 -0
  157. package/.next/server/chunks/5436.js +1 -0
  158. package/.next/server/chunks/5543.js +1 -0
  159. package/.next/server/chunks/569.js +1 -0
  160. package/.next/server/chunks/5895.js +16 -0
  161. package/.next/server/chunks/5986.js +3 -0
  162. package/.next/server/chunks/613.js +1 -0
  163. package/.next/server/chunks/6216.js +1 -0
  164. package/.next/server/chunks/6435.js +1 -0
  165. package/.next/server/chunks/6536.js +3 -0
  166. package/.next/server/chunks/6602.js +4 -0
  167. package/.next/server/chunks/6730.js +1 -0
  168. package/.next/server/chunks/6909.js +488 -0
  169. package/.next/server/chunks/7188.js +1 -0
  170. package/.next/server/chunks/7300.js +128 -0
  171. package/.next/server/chunks/7508.js +1 -0
  172. package/.next/server/chunks/7572.js +2 -0
  173. package/.next/server/chunks/8056.js +1 -0
  174. package/.next/server/chunks/8124.js +1 -0
  175. package/.next/server/chunks/8262.js +1 -0
  176. package/.next/server/chunks/8404.js +62 -0
  177. package/.next/server/chunks/8514.js +1 -0
  178. package/.next/server/chunks/8843.js +1 -0
  179. package/.next/server/chunks/9098.js +1 -0
  180. package/.next/server/chunks/9293.js +1 -0
  181. package/.next/server/chunks/9328.js +179 -0
  182. package/.next/server/chunks/94.js +1 -0
  183. package/.next/server/chunks/9579.js +1 -0
  184. package/.next/server/chunks/9631.js +16 -0
  185. package/.next/server/chunks/9692.js +6 -0
  186. package/.next/server/chunks/9739.js +108 -0
  187. package/.next/server/chunks/9803.js +22 -0
  188. package/.next/server/chunks/9835.js +1 -0
  189. package/.next/server/chunks/9842.js +1 -0
  190. package/.next/server/chunks/9861.js +128 -0
  191. package/.next/server/chunks/9995.js +1 -0
  192. package/.next/server/edge-runtime-webpack.js +2 -0
  193. package/.next/server/edge-runtime-webpack.js.map +1 -0
  194. package/.next/server/functions-config-manifest.json +21 -0
  195. package/.next/server/interception-route-rewrite-manifest.js +1 -0
  196. package/.next/server/middleware-build-manifest.js +1 -0
  197. package/.next/server/middleware-manifest.json +32 -0
  198. package/.next/server/middleware-react-loadable-manifest.js +1 -0
  199. package/.next/server/middleware.js +14 -0
  200. package/.next/server/middleware.js.map +1 -0
  201. package/.next/server/next-font-manifest.js +1 -0
  202. package/.next/server/next-font-manifest.json +1 -0
  203. package/.next/server/pages/404.html +1 -0
  204. package/.next/server/pages/500.html +1 -0
  205. package/.next/server/pages/_app.js +1 -0
  206. package/.next/server/pages/_app.js.nft.json +1 -0
  207. package/.next/server/pages/_document.js +1 -0
  208. package/.next/server/pages/_document.js.nft.json +1 -0
  209. package/.next/server/pages/_error.js +19 -0
  210. package/.next/server/pages/_error.js.nft.json +1 -0
  211. package/.next/server/pages-manifest.json +6 -0
  212. package/.next/server/server-reference-manifest.js +1 -0
  213. package/.next/server/server-reference-manifest.json +1 -0
  214. package/.next/server/webpack-runtime.js +1 -0
  215. package/.next/static/chunks/1217-407174d9b164a499.js +1 -0
  216. package/.next/static/chunks/146-ccee3b26755b68c8.js +1 -0
  217. package/.next/static/chunks/3335-5647a38ab2cfa88d.js +1 -0
  218. package/.next/static/chunks/3954-fe27ff41d9bf012d.js +1 -0
  219. package/.next/static/chunks/4108.d6ed46bc2fcab462.js +1 -0
  220. package/.next/static/chunks/4400-cdb1f7913ae34e09.js +1 -0
  221. package/.next/static/chunks/4895-712004156efeccf2.js +1 -0
  222. package/.next/static/chunks/5097-f07f6aeee3f60a33.js +1 -0
  223. package/.next/static/chunks/5235-990ba9c4c8446446.js +62 -0
  224. package/.next/static/chunks/6489-ecde2d94e57eb8a9.js +1 -0
  225. package/.next/static/chunks/6568-e4d2de23d9f8d347.js +1 -0
  226. package/.next/static/chunks/6727-d38536774bdb32d5.js +1 -0
  227. package/.next/static/chunks/6734-9d524ec49e4ba49c.js +1 -0
  228. package/.next/static/chunks/6744-dbfe3cc4ce461613.js +1 -0
  229. package/.next/static/chunks/6fe292aa-7126ff9d6732e864.js +1 -0
  230. package/.next/static/chunks/8566-5d4c89b722d9cee1.js +1 -0
  231. package/.next/static/chunks/8775-890699c74c28df61.js +1 -0
  232. package/.next/static/chunks/9045-731ff0865352dd95.js +1 -0
  233. package/.next/static/chunks/app/_not-found/page-ffead1b4e248e14d.js +1 -0
  234. package/.next/static/chunks/app/agents/[agentId]/page-0b5c2838354d0eba.js +1 -0
  235. package/.next/static/chunks/app/api/agents/[agentId]/respond/route-7e2f82a91b10b7e2.js +1 -0
  236. package/.next/static/chunks/app/api/images/[rootId]/[file]/route-7e2f82a91b10b7e2.js +1 -0
  237. package/.next/static/chunks/app/api/oauth/callback/route-7e2f82a91b10b7e2.js +1 -0
  238. package/.next/static/chunks/app/api/oauth/start/route-7e2f82a91b10b7e2.js +1 -0
  239. package/.next/static/chunks/app/api/roots/[id]/attachments/route-7e2f82a91b10b7e2.js +1 -0
  240. package/.next/static/chunks/app/api/roots/[id]/chat/[topicId]/send/route-7e2f82a91b10b7e2.js +1 -0
  241. package/.next/static/chunks/app/api/roots/[id]/chat/[topicId]/stop/route-7e2f82a91b10b7e2.js +1 -0
  242. package/.next/static/chunks/app/api/roots/[id]/chat/[topicId]/stream/route-7e2f82a91b10b7e2.js +1 -0
  243. package/.next/static/chunks/app/api/roots/[id]/dashboard/route-7e2f82a91b10b7e2.js +1 -0
  244. package/.next/static/chunks/app/api/roots/[id]/suggestions/route-7e2f82a91b10b7e2.js +1 -0
  245. package/.next/static/chunks/app/api/utilities/[scope]/[id]/bundle.js/route-7e2f82a91b10b7e2.js +1 -0
  246. package/.next/static/chunks/app/api/utilities/[scope]/[id]/host/route-7e2f82a91b10b7e2.js +1 -0
  247. package/.next/static/chunks/app/api/utilities/[scope]/[id]/host-api.mjs/route-7e2f82a91b10b7e2.js +1 -0
  248. package/.next/static/chunks/app/api/utilities/[scope]/[id]/host-ui.mjs/route-7e2f82a91b10b7e2.js +1 -0
  249. package/.next/static/chunks/app/api/utilities/[scope]/[id]/iframe/route-7e2f82a91b10b7e2.js +1 -0
  250. package/.next/static/chunks/app/api/utilities/[scope]/[id]/style.css/route-7e2f82a91b10b7e2.js +1 -0
  251. package/.next/static/chunks/app/audit/page-e3445076d462aa80.js +1 -0
  252. package/.next/static/chunks/app/layout-c7a35075cfbfa3e3.js +1 -0
  253. package/.next/static/chunks/app/onboarding/page-cde5b92b13b03c63.js +1 -0
  254. package/.next/static/chunks/app/page-ddaeffdc9a15f597.js +1 -0
  255. package/.next/static/chunks/app/roots/[id]/chat/[topicId]/page-1b55f68984817d29.js +1 -0
  256. package/.next/static/chunks/app/roots/[id]/kb/[...slug]/page-d4358cb6042740c4.js +1 -0
  257. package/.next/static/chunks/app/roots/[id]/layout-7e2f82a91b10b7e2.js +1 -0
  258. package/.next/static/chunks/app/roots/[id]/page-703d96bf8208af2f.js +1 -0
  259. package/.next/static/chunks/app/roots/[id]/workflows/[wfId]/page-738e8e4128baa722.js +1 -0
  260. package/.next/static/chunks/app/roots/[id]/workflows/page-e3445076d462aa80.js +1 -0
  261. package/.next/static/chunks/app/roots/new/page-534769dce46d0d29.js +1 -0
  262. package/.next/static/chunks/app/settings/page-86ee3d07ea1acbc7.js +1 -0
  263. package/.next/static/chunks/app/share/[id]/file/page-93e0105d7903f777.js +1 -0
  264. package/.next/static/chunks/app/share/[id]/page-5bbc8503cb9a9eeb.js +1 -0
  265. package/.next/static/chunks/app/utilities/[scope]/[id]/page-72546d245b840091.js +1 -0
  266. package/.next/static/chunks/app/utilities/page-9f949d831421d314.js +1 -0
  267. package/.next/static/chunks/framework-aaa7c1a953276299.js +1 -0
  268. package/.next/static/chunks/main-app-ebe67847147d19aa.js +1 -0
  269. package/.next/static/chunks/main-bfb98fc1d6aa1d45.js +1 -0
  270. package/.next/static/chunks/pages/_app-bf8bc157ace53d59.js +1 -0
  271. package/.next/static/chunks/pages/_error-da89ab2956f0cf38.js +1 -0
  272. package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  273. package/.next/static/chunks/webpack-2e8cca5826414cc6.js +1 -0
  274. package/.next/static/css/87e01f779d555d04.css +1 -0
  275. package/.next/static/p8t15rbWhT5Rrs5fOXWZ6/_buildManifest.js +1 -0
  276. package/.next/static/p8t15rbWhT5Rrs5fOXWZ6/_ssgManifest.js +1 -0
  277. package/.next/trace +46 -0
  278. package/.next/types/app/agents/[agentId]/page.ts +84 -0
  279. package/.next/types/app/api/agents/[agentId]/respond/route.ts +347 -0
  280. package/.next/types/app/api/images/[rootId]/[file]/route.ts +347 -0
  281. package/.next/types/app/api/oauth/callback/route.ts +347 -0
  282. package/.next/types/app/api/oauth/start/route.ts +347 -0
  283. package/.next/types/app/api/roots/[id]/attachments/route.ts +347 -0
  284. package/.next/types/app/api/roots/[id]/chat/[topicId]/send/route.ts +347 -0
  285. package/.next/types/app/api/roots/[id]/chat/[topicId]/stop/route.ts +347 -0
  286. package/.next/types/app/api/roots/[id]/chat/[topicId]/stream/route.ts +347 -0
  287. package/.next/types/app/api/roots/[id]/dashboard/route.ts +347 -0
  288. package/.next/types/app/api/roots/[id]/suggestions/route.ts +347 -0
  289. package/.next/types/app/api/utilities/[scope]/[id]/bundle.js/route.ts +347 -0
  290. package/.next/types/app/api/utilities/[scope]/[id]/host/route.ts +347 -0
  291. package/.next/types/app/api/utilities/[scope]/[id]/host-api.mjs/route.ts +347 -0
  292. package/.next/types/app/api/utilities/[scope]/[id]/host-ui.mjs/route.ts +347 -0
  293. package/.next/types/app/api/utilities/[scope]/[id]/iframe/route.ts +347 -0
  294. package/.next/types/app/api/utilities/[scope]/[id]/style.css/route.ts +347 -0
  295. package/.next/types/app/audit/page.ts +84 -0
  296. package/.next/types/app/onboarding/page.ts +84 -0
  297. package/.next/types/app/page.ts +84 -0
  298. package/.next/types/app/roots/[id]/chat/[topicId]/page.ts +84 -0
  299. package/.next/types/app/roots/[id]/kb/[...slug]/page.ts +84 -0
  300. package/.next/types/app/roots/[id]/layout.ts +84 -0
  301. package/.next/types/app/roots/[id]/page.ts +84 -0
  302. package/.next/types/app/roots/[id]/workflows/[wfId]/page.ts +84 -0
  303. package/.next/types/app/roots/[id]/workflows/page.ts +84 -0
  304. package/.next/types/app/roots/new/page.ts +84 -0
  305. package/.next/types/app/settings/page.ts +84 -0
  306. package/.next/types/app/share/[id]/file/page.ts +84 -0
  307. package/.next/types/app/share/[id]/page.ts +84 -0
  308. package/.next/types/app/utilities/[scope]/[id]/page.ts +84 -0
  309. package/.next/types/app/utilities/page.ts +84 -0
  310. package/.next/types/cache-life.d.ts +141 -0
  311. package/.next/types/package.json +1 -0
  312. package/.next/types/routes.d.ts +103 -0
  313. package/.next/types/validator.ts +349 -0
  314. package/README.md +72 -0
  315. package/dist/bin/cli.js +82 -0
  316. package/dist/bin/cli.js.map +1 -0
  317. package/dist/lib/reflex/agents/backend.js +14 -0
  318. package/dist/lib/reflex/agents/backend.js.map +1 -0
  319. package/dist/lib/reflex/agents/claude-code.js +48 -0
  320. package/dist/lib/reflex/agents/claude-code.js.map +1 -0
  321. package/dist/lib/reflex/agents/codex.js +46 -0
  322. package/dist/lib/reflex/agents/codex.js.map +1 -0
  323. package/dist/lib/reflex/agents/index.js +13 -0
  324. package/dist/lib/reflex/agents/index.js.map +1 -0
  325. package/dist/lib/reflex/agents/prompts.js +228 -0
  326. package/dist/lib/reflex/agents/prompts.js.map +1 -0
  327. package/dist/lib/reflex/commands/chat.js +41 -0
  328. package/dist/lib/reflex/commands/chat.js.map +1 -0
  329. package/dist/lib/reflex/commands/init.js +38 -0
  330. package/dist/lib/reflex/commands/init.js.map +1 -0
  331. package/dist/lib/reflex/commands/start.js +64 -0
  332. package/dist/lib/reflex/commands/start.js.map +1 -0
  333. package/dist/lib/reflex/commands/watch.js +137 -0
  334. package/dist/lib/reflex/commands/watch.js.map +1 -0
  335. package/dist/lib/reflex/config.js +42 -0
  336. package/dist/lib/reflex/config.js.map +1 -0
  337. package/dist/lib/reflex/ignore.js +83 -0
  338. package/dist/lib/reflex/ignore.js.map +1 -0
  339. package/dist/lib/reflex/kb.js +48 -0
  340. package/dist/lib/reflex/kb.js.map +1 -0
  341. package/dist/lib/reflex/paths.js +33 -0
  342. package/dist/lib/reflex/paths.js.map +1 -0
  343. package/dist/lib/reflex/prompts/defaults.js +363 -0
  344. package/dist/lib/reflex/prompts/defaults.js.map +1 -0
  345. package/dist/lib/reflex/prompts/render.js +14 -0
  346. package/dist/lib/reflex/prompts/render.js.map +1 -0
  347. package/dist/lib/reflex/prompts/store.js +54 -0
  348. package/dist/lib/reflex/prompts/store.js.map +1 -0
  349. package/dist/lib/reflex/walker.js +55 -0
  350. package/dist/lib/reflex/walker.js.map +1 -0
  351. package/next.config.ts +33 -0
  352. package/package.json +87 -0
  353. package/packages/utilities/learn-anything/README.md +41 -0
  354. package/packages/utilities/learn-anything/actions/_json.ts +191 -0
  355. package/packages/utilities/learn-anything/actions/_store.ts +248 -0
  356. package/packages/utilities/learn-anything/actions/buildModule.ts +487 -0
  357. package/packages/utilities/learn-anything/actions/explainSelection.ts +64 -0
  358. package/packages/utilities/learn-anything/actions/generateOutline.ts +170 -0
  359. package/packages/utilities/learn-anything/actions/generateQuiz.ts +72 -0
  360. package/packages/utilities/learn-anything/actions/generateTrainer.ts +106 -0
  361. package/packages/utilities/learn-anything/actions/refreshCourseCard.ts +76 -0
  362. package/packages/utilities/learn-anything/actions/tutorAsk.ts +93 -0
  363. package/packages/utilities/learn-anything/article-view.tsx +464 -0
  364. package/packages/utilities/learn-anything/manifest.json +42 -0
  365. package/packages/utilities/learn-anything/ui.tsx +1589 -0
@@ -0,0 +1,55 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ import { IgnoreStack } from "./ignore.js";
4
+ /**
5
+ * Walk `root` honoring nested `.reflexignore` files and a default prune list.
6
+ * Yields both directories and files so callers can drive per-dir analysis.
7
+ */
8
+ export async function* walk(root, options = {}) {
9
+ const { maxDepth = Infinity, followSymlinks = false } = options;
10
+ const rootAbs = path.resolve(root);
11
+ const initialStack = await IgnoreStack.create(rootAbs);
12
+ yield { abs: rootAbs, rel: ".", isDir: true };
13
+ yield* descend(rootAbs, rootAbs, initialStack, 0, maxDepth, followSymlinks);
14
+ }
15
+ async function* descend(root, dir, stack, depth, maxDepth, followSymlinks) {
16
+ if (depth >= maxDepth)
17
+ return;
18
+ let entries;
19
+ try {
20
+ entries = await fs.readdir(dir, { withFileTypes: true });
21
+ }
22
+ catch {
23
+ return;
24
+ }
25
+ entries.sort((a, b) => a.name.localeCompare(b.name));
26
+ for (const e of entries) {
27
+ const abs = path.join(dir, e.name);
28
+ if (stack.ignores(abs))
29
+ continue;
30
+ const isSymlink = e.isSymbolicLink();
31
+ if (isSymlink && !followSymlinks)
32
+ continue;
33
+ const isDir = e.isDirectory() || (isSymlink && (await isLinkedDir(abs)));
34
+ const rel = posixRel(root, abs);
35
+ yield { abs, rel, isDir };
36
+ if (isDir) {
37
+ const child = await stack.enter(abs);
38
+ yield* descend(root, abs, child, depth + 1, maxDepth, followSymlinks);
39
+ }
40
+ }
41
+ }
42
+ async function isLinkedDir(abs) {
43
+ try {
44
+ const s = await fs.stat(abs);
45
+ return s.isDirectory();
46
+ }
47
+ catch {
48
+ return false;
49
+ }
50
+ }
51
+ function posixRel(root, abs) {
52
+ const r = path.relative(root, abs);
53
+ return r.split(path.sep).join("/");
54
+ }
55
+ //# sourceMappingURL=walker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walker.js","sourceRoot":"","sources":["../../../lib/reflex/walker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkB1C;;;GAGG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,IAAI,CACzB,IAAY,EACZ,UAAuB,EAAE;IAEzB,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAAE,cAAc,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,YAAY,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC9C,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;AAC9E,CAAC;AAED,KAAK,SAAS,CAAC,CAAC,OAAO,CACrB,IAAY,EACZ,GAAW,EACX,KAAkB,EAClB,KAAa,EACb,QAAgB,EAChB,cAAuB;IAEvB,IAAI,KAAK,IAAI,QAAQ;QAAE,OAAO;IAC9B,IAAI,OAAmC,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;IACT,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACrD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,SAAS;QACjC,MAAM,SAAS,GAAG,CAAC,CAAC,cAAc,EAAE,CAAC;QACrC,IAAI,SAAS,IAAI,CAAC,cAAc;YAAE,SAAS;QAC3C,MAAM,KAAK,GAAG,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACzE,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAChC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QAC1B,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACrC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,GAAW;IACpC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY,EAAE,GAAW;IACzC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACnC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACrC,CAAC"}
package/next.config.ts ADDED
@@ -0,0 +1,33 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {
4
+ // Allow server components/actions in our local app to spawn child processes
5
+ // and interact with the local filesystem.
6
+ serverExternalPackages: [
7
+ "chokidar",
8
+ "execa",
9
+ "esbuild",
10
+ "sharp",
11
+ "@tailwindcss/node",
12
+ "@tailwindcss/oxide",
13
+ "tailwindcss",
14
+ "lightningcss",
15
+ ],
16
+ // The shared `lib/reflex/` modules use `.js` extensions in their imports
17
+ // (required by Node's NodeNext resolver for the CLI build). Tell webpack
18
+ // and Turbopack to fall back to `.ts`/`.tsx` when resolving them.
19
+ turbopack: {
20
+ resolveExtensions: [".tsx", ".ts", ".jsx", ".js", ".json"],
21
+ resolveAlias: {},
22
+ },
23
+ webpack: (config) => {
24
+ config.resolve = config.resolve ?? {};
25
+ config.resolve.extensionAlias = {
26
+ ".js": [".ts", ".tsx", ".js"],
27
+ ".jsx": [".tsx", ".jsx"],
28
+ };
29
+ return config;
30
+ },
31
+ };
32
+
33
+ export default nextConfig;
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "reflex-agent",
3
+ "version": "0.2.1",
4
+ "private": false,
5
+ "description": "Local-first knowledge base built by an agent over a chosen directory.",
6
+ "license": "MIT",
7
+ "author": "legostin",
8
+ "homepage": "https://github.com/legostin/reflex-agent#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/legostin/reflex-agent.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/legostin/reflex-agent/issues"
15
+ },
16
+ "type": "module",
17
+ "bin": {
18
+ "reflex": "./dist/bin/cli.js"
19
+ },
20
+ "files": [
21
+ "dist",
22
+ ".next",
23
+ "next.config.ts",
24
+ "packages/utilities",
25
+ "README.md",
26
+ "LICENSE"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "scripts": {
32
+ "dev": "next dev -p 3210",
33
+ "start": "next start -p 3210",
34
+ "build": "next build && pnpm run build:cli",
35
+ "build:cli": "tsc -p tsconfig.cli.json",
36
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.cli.json --noEmit",
37
+ "prepack": "node -e \"require('fs').rmSync('.next/cache', { recursive: true, force: true })\"",
38
+ "prepublishOnly": "pnpm run build"
39
+ },
40
+ "engines": {
41
+ "node": ">=20"
42
+ },
43
+ "packageManager": "pnpm@10.29.2",
44
+ "dependencies": {
45
+ "@modelcontextprotocol/sdk": "^1.29.0",
46
+ "@openai/codex-sdk": "0.133.0",
47
+ "@radix-ui/react-scroll-area": "^1",
48
+ "@radix-ui/react-separator": "^1",
49
+ "@radix-ui/react-slot": "^1",
50
+ "@radix-ui/react-tabs": "^1",
51
+ "@tailwindcss/node": "^4.3.0",
52
+ "@tailwindcss/postcss": "^4",
53
+ "@tailwindcss/typography": "^0.5.19",
54
+ "chokidar": "^4",
55
+ "class-variance-authority": "^0.7",
56
+ "clsx": "^2",
57
+ "commander": "^14",
58
+ "esbuild": "^0.28.0",
59
+ "execa": "^9",
60
+ "gray-matter": "^4.0.3",
61
+ "highlight.js": "^11.11.1",
62
+ "ignore": "^7",
63
+ "lucide-react": "^0.475",
64
+ "mermaid": "^11.15.0",
65
+ "next": "^15",
66
+ "next-themes": "^0.4.6",
67
+ "radix-ui": "^1.4.3",
68
+ "react": "^19",
69
+ "react-dom": "^19",
70
+ "react-markdown": "^9",
71
+ "rehype-highlight": "^7.0.2",
72
+ "remark-gfm": "^4",
73
+ "server-only": "^0.0.1",
74
+ "sharp": "^0.34.5",
75
+ "sonner": "^1",
76
+ "tailwind-merge": "^2",
77
+ "tailwindcss": "^4",
78
+ "tw-animate-css": "^1",
79
+ "zod": "^4"
80
+ },
81
+ "devDependencies": {
82
+ "@types/node": "^24",
83
+ "@types/react": "^19",
84
+ "@types/react-dom": "^19",
85
+ "typescript": "^6"
86
+ }
87
+ }
@@ -0,0 +1,41 @@
1
+ # 🎓 Изучи что угодно
2
+
3
+ Универсальный AI-наставник. Введи тему → агент задаёт 2-4 уточняющих вопроса (про уровень, цель, время, формат) → собирает программу 5-9 модулей → каждый модуль с длинной статьёй, видео, иллюстрациями, схемами (mermaid), тестом, домашкой и интерактивным тренажёром на canvas.
4
+
5
+ ## Возможности
6
+
7
+ - **Wizard в агентном режиме** — вопросы НЕ хардкоженные, агент сам решает что важно спросить под конкретную тему. «Хочу научиться рисовать акварелью» и «Хочу выучить Python» приведут к разным вопросам.
8
+ - **Программа курса** — генерируется с целями и оценкой времени.
9
+ - **Модуль = статья 800-2000 слов** + видео (YouTube) + ссылки на источники + изображения (CC) + mermaid-схемы + 3-5 домашних заданий.
10
+ - **Тест** — 5-7 multiple-choice вопросов сгенерированных из статьи, мгновенная проверка с объяснениями.
11
+ - **Прогресс** — отметка пройденности + результат теста, сохраняется в KB.
12
+ - **Объяснить выделенное** — выдели любой кусок статьи → агент даст подробное объяснение с примерами.
13
+ - **Тренажёр** — агент пишет standalone HTML/JS/canvas под идею (или сам предложит идею), Reflex рендерит в sandboxed iframe.
14
+
15
+ ## KB-схемы
16
+
17
+ - `course` — корень курса: `meta.courseId`, `meta.topic`, `meta.modules` (JSON), `meta.progress` (JSON), `meta.wizardAnswers` (JSON), `meta.createdAt`.
18
+ - `course-module` — материал модуля: `meta.courseId`, `meta.moduleId`, JSON-поля `videos`/`links`/`images`/`diagrams`/`homework`, body = статья.
19
+ - `course-trainer` — HTML тренажёра в `meta.html` (capped ≈60KB).
20
+ - `course-note` — пользовательские заметки в модуле (опц., пока не используется).
21
+
22
+ ## Server actions
23
+
24
+ - `tutorAsk({topic, history, forceFinish?})` — следующий вопрос wizard или `{done:true}`.
25
+ - `generateOutline({topic, history})` — программа курса + сохранение KB.
26
+ - `buildModule({courseId, moduleId, moduleTitle, moduleObjective, topic})` — материал модуля.
27
+ - `generateQuiz({moduleTitle, moduleObjective, article})` — тест.
28
+ - `explainSelection({selection, context, topic, moduleTitle})` — глубокое объяснение фрагмента.
29
+ - `generateTrainer({courseId, moduleId, moduleTitle, moduleObjective, prompt?})` — HTML тренажёр.
30
+ - `refreshCourseCard()` — обновление dashboard-карточки (число активных курсов + средний прогресс).
31
+
32
+ ## Разрешения
33
+
34
+ `llm.chat/quick`, `kb.read/write` для своих kinds, `fs.sandbox` (для будущего кэша), `web.fetch` с whitelist (wikipedia, mdn, youtube, ...), `web.search`, `audit.write`, `workers.enabled`, `agent.invoke`.
35
+
36
+ ## Ограничения v0.1
37
+
38
+ - Картинки не качаются локально (используются URL'ы CC-источников); подписаны в whitelist.
39
+ - Mermaid-схемы рендерятся как code-block; embed-рендер придёт в v0.2.
40
+ - Тренажёры в `srcdoc` iframe — без доступа к host RPC (только клиентский JS+canvas).
41
+ - Прогресс хранится в frontmatter курса; кэш на mtime ещё не оптимизирован.
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Resilient JSON extraction from LLM/agent output.
3
+ *
4
+ * Strategies tried in order:
5
+ * 1. Strip ```json/``` fences then JSON.parse the whole content.
6
+ * 2. Find the outermost balanced `{...}` block via bracket-counter.
7
+ * 3. Last-resort greedy `/\{[\s\S]*\}/`.
8
+ *
9
+ * Returns `null` if every strategy fails — callers usually retry the
10
+ * LLM call once with a stricter "JSON only, no markdown" prompt.
11
+ */
12
+ export function extractJson<T = unknown>(raw: string): T | null {
13
+ if (!raw || typeof raw !== "string") return null;
14
+ const candidates: string[] = [];
15
+
16
+ // Strategy 1: strip outer fences.
17
+ const fence = /```(?:json)?\s*([\s\S]*?)\s*```/.exec(raw);
18
+ if (fence) candidates.push(fence[1]!.trim());
19
+
20
+ // Strategy 2: balanced-brace scan from first `{`.
21
+ const start = raw.indexOf("{");
22
+ if (start >= 0) {
23
+ let depth = 0;
24
+ let inStr = false;
25
+ let escape = false;
26
+ for (let i = start; i < raw.length; i++) {
27
+ const ch = raw[i]!;
28
+ if (escape) {
29
+ escape = false;
30
+ continue;
31
+ }
32
+ if (ch === "\\") {
33
+ escape = true;
34
+ continue;
35
+ }
36
+ if (ch === '"') {
37
+ inStr = !inStr;
38
+ continue;
39
+ }
40
+ if (inStr) continue;
41
+ if (ch === "{") depth++;
42
+ else if (ch === "}") {
43
+ depth--;
44
+ if (depth === 0) {
45
+ candidates.push(raw.slice(start, i + 1));
46
+ break;
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ // Strategy 3: greedy fallback.
53
+ const greedy = /\{[\s\S]*\}/.exec(raw);
54
+ if (greedy) candidates.push(greedy[0]);
55
+
56
+ for (const c of candidates) {
57
+ try {
58
+ return JSON.parse(c) as T;
59
+ } catch {
60
+ // try next
61
+ }
62
+ }
63
+ return null;
64
+ }
65
+
66
+ /**
67
+ * Short snippet of an agent response, for inclusion in error toasts so
68
+ * the user can see what went wrong without us shipping the full reply.
69
+ */
70
+ export function snippet(s: string, max = 240): string {
71
+ if (!s) return "(пусто)";
72
+ const trimmed = s.trim();
73
+ if (trimmed.length <= max) return trimmed;
74
+ return trimmed.slice(0, max) + "…";
75
+ }
76
+
77
+ /**
78
+ * Self-correcting agent loop for JSON-shaped responses.
79
+ *
80
+ * • Up to `maxAttempts` LLM calls (default 4).
81
+ * • On parse/validation failure we don't just say "try again" — we
82
+ * hand the LLM its own bad answer + a strict format reminder, and
83
+ * ask it to FIRST diagnose what was wrong (one phrase) THEN return
84
+ * the corrected JSON. The diagnosis is throwaway; only the JSON is
85
+ * parsed. Single round-trip per attempt.
86
+ * • `validate` is the gatekeeper — return non-null when the parsed
87
+ * payload satisfies the caller's structural needs.
88
+ *
89
+ * Returns either the validated value with attempt count, or a
90
+ * structured failure with the last raw text for diagnostics.
91
+ */
92
+ export interface JsonAgentArgs<T> {
93
+ /** Initial prompt — should already include the JSON-only instruction. */
94
+ prompt: string;
95
+ /** LLM caller (e.g. (p) => reflex.agent.invoke({prompt: p})). */
96
+ invoke: (prompt: string) => Promise<{ text?: string }>;
97
+ /** Returns the validated value, or null if shape is wrong / empty. */
98
+ validate: (parsed: unknown) => T | null;
99
+ /** Default 4. The LLM call is the slow part — we cap to avoid runaways. */
100
+ maxAttempts?: number;
101
+ /** Optional one-line description of the expected shape; surfaces in
102
+ * the reflection prompt verbatim. */
103
+ shapeHint?: string;
104
+ }
105
+
106
+ export interface JsonAgentSuccess<T> {
107
+ ok: true;
108
+ value: T;
109
+ attempts: number;
110
+ }
111
+
112
+ export interface JsonAgentFailure {
113
+ ok: false;
114
+ attempts: number;
115
+ lastText: string;
116
+ /** Why we gave up — "no-json" / "invalid-shape" / "empty-result". */
117
+ reason: "no-json" | "invalid-shape" | "empty-result";
118
+ }
119
+
120
+ export async function callJsonAgent<T>(
121
+ args: JsonAgentArgs<T>,
122
+ ): Promise<JsonAgentSuccess<T> | JsonAgentFailure> {
123
+ const max = Math.max(1, args.maxAttempts ?? 4);
124
+ let lastText = "";
125
+ let lastReason: JsonAgentFailure["reason"] = "no-json";
126
+
127
+ for (let attempt = 1; attempt <= max; attempt++) {
128
+ const prompt =
129
+ attempt === 1
130
+ ? args.prompt
131
+ : buildReflectionPrompt(args.prompt, lastText, lastReason, args.shapeHint, attempt);
132
+
133
+ const r = await args.invoke(prompt);
134
+ lastText = r.text ?? "";
135
+ const json = extractJson<unknown>(lastText);
136
+ if (!json) {
137
+ lastReason = "no-json";
138
+ continue;
139
+ }
140
+ const validated = args.validate(json);
141
+ if (validated == null) {
142
+ // Distinguish empty vs malformed for the reflection prompt.
143
+ lastReason = isEmptyShape(json) ? "empty-result" : "invalid-shape";
144
+ continue;
145
+ }
146
+ return { ok: true, value: validated, attempts: attempt };
147
+ }
148
+ return { ok: false, attempts: max, lastText, reason: lastReason };
149
+ }
150
+
151
+ function isEmptyShape(v: unknown): boolean {
152
+ if (v == null) return true;
153
+ if (Array.isArray(v)) return v.length === 0;
154
+ if (typeof v === "object") return Object.keys(v as object).length === 0;
155
+ return false;
156
+ }
157
+
158
+ function buildReflectionPrompt(
159
+ original: string,
160
+ lastText: string,
161
+ reason: JsonAgentFailure["reason"],
162
+ shape: string | undefined,
163
+ attempt: number,
164
+ ): string {
165
+ const reasonLine =
166
+ reason === "no-json"
167
+ ? "Твой предыдущий ответ нельзя было распарсить как JSON (вероятно: markdown-фенсы, лишний текст до/после, незакрытые скобки, одинарные кавычки)."
168
+ : reason === "empty-result"
169
+ ? "Твой предыдущий ответ был валидным JSON но пустым (нет нужных полей или массивы пустые)."
170
+ : "Твой предыдущий ответ был валидным JSON, но не соответствовал ожидаемой схеме (не все поля заполнены или неверные типы).";
171
+ const lines = [
172
+ original,
173
+ "",
174
+ "## КРИТИЧНО — это попытка номер " + attempt,
175
+ reasonLine,
176
+ "",
177
+ "Вот что ты вернул в прошлый раз (фрагмент):",
178
+ "```",
179
+ snippet(lastText, 600),
180
+ "```",
181
+ "",
182
+ "Теперь:",
183
+ " 1. ОДНОЙ строкой комментария `// причина: ...` опиши что было не так (для самопроверки).",
184
+ " 2. Сразу после комментария — корректный JSON.",
185
+ shape
186
+ ? `\nОжидаемая форма:\n${shape}`
187
+ : "",
188
+ "\nВНИМАНИЕ: ответ должен начинаться или с `//` (комментарий) или с `{`. Никаких ```fence```, никакой прозы перед JSON.",
189
+ ];
190
+ return lines.filter(Boolean).join("\n");
191
+ }
@@ -0,0 +1,248 @@
1
+ import { reflex } from "@host/api";
2
+
3
+ /**
4
+ * Shared course state store. Lives in the utility's `data/` sandbox
5
+ * (one JSON file per course at `courses/<courseId>.json`) — bypasses
6
+ * the frontmatter round-tripping problem (long JSON strings → multi-line
7
+ * YAML → our naive client-side parser drops them). The companion KB
8
+ * entry of `kind:"course"` stays for human visibility / provenance
9
+ * badges, but it's NOT the source of truth.
10
+ *
11
+ * The body markdown rendered into the KB entry is regenerated from the
12
+ * full state on every write — so editing in a KB viewer would be
13
+ * overwritten next save (matches "agent-managed" data model).
14
+ */
15
+
16
+ export interface CourseState {
17
+ courseId: string;
18
+ topic: string;
19
+ modules: Array<{
20
+ id: string;
21
+ title: string;
22
+ objective: string;
23
+ estMinutes: number;
24
+ }>;
25
+ progress: Record<string, { completed?: boolean; quizScore?: number }>;
26
+ wizardAnswers: Array<{ question: string; answer: string }>;
27
+ createdAt: string;
28
+ /** Bumped on every write to drive list-view re-renders. */
29
+ updatedAt: string;
30
+ }
31
+
32
+ const DIR = "courses";
33
+
34
+ export async function writeCourse(state: CourseState): Promise<void> {
35
+ const path = `${DIR}/${state.courseId}.json`;
36
+ await reflex.fs.write({
37
+ path,
38
+ content: JSON.stringify(state, null, 2),
39
+ });
40
+ }
41
+
42
+ export async function readCourse(courseId: string): Promise<CourseState | null> {
43
+ try {
44
+ const { content } = await reflex.fs.read({
45
+ path: `${DIR}/${courseId}.json`,
46
+ });
47
+ return JSON.parse(content) as CourseState;
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
52
+
53
+ export async function listCourses(): Promise<CourseState[]> {
54
+ const out: CourseState[] = [];
55
+ try {
56
+ const { entries } = await reflex.fs.list({ path: DIR });
57
+ for (const e of entries) {
58
+ if (e.isDir) continue;
59
+ if (!e.name.endsWith(".json")) continue;
60
+ const id = e.name.slice(0, -5);
61
+ const c = await readCourse(id);
62
+ if (c) out.push(c);
63
+ }
64
+ } catch {
65
+ /* dir not created yet → empty list */
66
+ }
67
+ // Migration fallback: pre-0.2 versions stored course state in KB
68
+ // frontmatter (which broke on long multi-line YAML). Pick up anything
69
+ // KB has that fs doesn't, hydrate from there, and persist to fs so
70
+ // the next open is fast and complete.
71
+ try {
72
+ const seen = new Set(out.map((c) => c.courseId));
73
+ const kb = (await reflex.kb.list({ kind: "course" })) ?? [];
74
+ for (const k of kb) {
75
+ try {
76
+ const { content } = await reflex.kb.read({ relPath: k.relPath });
77
+ const fm = parseFrontmatter(content);
78
+ const courseId = stringField(fm, "courseId") || baseSlug(k.relPath);
79
+ if (!courseId || seen.has(courseId)) continue;
80
+ const topic =
81
+ stringField(fm, "topic") || k.title || courseId;
82
+ const modulesFm = fm?.modules;
83
+ // Best-effort: parse JSON-string frontmatter OR rebuild a stub
84
+ // outline from the body's "1. **Title** — objective" lines.
85
+ const modules =
86
+ parseModulesField(modulesFm) ?? parseModulesFromBody(content);
87
+ if (modules.length === 0) continue;
88
+ const progress =
89
+ parseProgressField(fm?.progress) ?? {};
90
+ const wizardAnswers =
91
+ parseWizardField(fm?.wizardAnswers) ?? [];
92
+ const createdAt =
93
+ stringField(fm, "createdAt") || k.modifiedAt || new Date().toISOString();
94
+ const migrated: CourseState = {
95
+ courseId,
96
+ topic,
97
+ modules,
98
+ progress,
99
+ wizardAnswers,
100
+ createdAt,
101
+ updatedAt: new Date().toISOString(),
102
+ };
103
+ out.push(migrated);
104
+ seen.add(courseId);
105
+ // Persist so we don't pay the KB scan next time.
106
+ await writeCourse(migrated);
107
+ } catch {
108
+ /* skip malformed entry */
109
+ }
110
+ }
111
+ } catch {
112
+ /* kb.list unavailable — fine, just no migration */
113
+ }
114
+ return out;
115
+ }
116
+
117
+ // ---------------------------------------------------------------------------
118
+ // KB migration helpers — only used by the fallback above.
119
+
120
+ function parseFrontmatter(raw: string): Record<string, unknown> | null {
121
+ const m = /^---\n([\s\S]*?)\n---/.exec(raw);
122
+ if (!m) return null;
123
+ const out: Record<string, unknown> = {};
124
+ // Crude but tolerant: collect multi-line values when indented or
125
+ // explicitly quoted with single quotes. Sufficient for old courses
126
+ // that wrapped a long JSON string under a single key.
127
+ const lines = m[1]!.split("\n");
128
+ let curKey: string | null = null;
129
+ let curBuf = "";
130
+ const flush = () => {
131
+ if (curKey == null) return;
132
+ let v = curBuf.trim();
133
+ // Strip outer quotes if present.
134
+ v = v.replace(/^['"]|['"]$/g, "");
135
+ out[curKey] = v;
136
+ curKey = null;
137
+ curBuf = "";
138
+ };
139
+ for (const line of lines) {
140
+ if (/^\S/.test(line) && line.includes(":")) {
141
+ flush();
142
+ const i = line.indexOf(":");
143
+ curKey = line.slice(0, i).trim();
144
+ curBuf = line.slice(i + 1);
145
+ } else if (curKey != null) {
146
+ curBuf += "\n" + line;
147
+ }
148
+ }
149
+ flush();
150
+ return out;
151
+ }
152
+
153
+ function stringField(fm: Record<string, unknown> | null, key: string): string {
154
+ return fm && typeof fm[key] === "string" ? (fm[key] as string) : "";
155
+ }
156
+
157
+ function parseModulesField(v: unknown): CourseState["modules"] | null {
158
+ if (typeof v !== "string") return null;
159
+ try {
160
+ const parsed = JSON.parse(v);
161
+ if (!Array.isArray(parsed)) return null;
162
+ return parsed
163
+ .filter(
164
+ (x): x is { id: string; title: string; objective?: string } =>
165
+ x &&
166
+ typeof x === "object" &&
167
+ typeof (x as { id?: unknown }).id === "string",
168
+ )
169
+ .map((x) => ({
170
+ id: x.id,
171
+ title:
172
+ typeof (x as { title?: unknown }).title === "string"
173
+ ? (x as { title: string }).title
174
+ : x.id,
175
+ objective:
176
+ typeof (x as { objective?: unknown }).objective === "string"
177
+ ? (x as { objective: string }).objective
178
+ : "",
179
+ estMinutes:
180
+ typeof (x as { estMinutes?: unknown }).estMinutes === "number"
181
+ ? (x as { estMinutes: number }).estMinutes
182
+ : 30,
183
+ }));
184
+ } catch {
185
+ return null;
186
+ }
187
+ }
188
+
189
+ function parseProgressField(v: unknown): CourseState["progress"] | null {
190
+ if (typeof v !== "string") return null;
191
+ try {
192
+ const p = JSON.parse(v);
193
+ return p && typeof p === "object" ? (p as CourseState["progress"]) : null;
194
+ } catch {
195
+ return null;
196
+ }
197
+ }
198
+
199
+ function parseWizardField(v: unknown): CourseState["wizardAnswers"] | null {
200
+ if (typeof v !== "string") return null;
201
+ try {
202
+ const p = JSON.parse(v);
203
+ return Array.isArray(p) ? (p as CourseState["wizardAnswers"]) : null;
204
+ } catch {
205
+ return null;
206
+ }
207
+ }
208
+
209
+ function parseModulesFromBody(raw: string): CourseState["modules"] {
210
+ // Body shape from old generateOutline: "1. **Title** — objective (~N мин)"
211
+ const out: CourseState["modules"] = [];
212
+ const re = /^\s*(\d+)\.\s+\*\*(.+?)\*\*\s*[—-]\s*(.*?)(?:\s*\(~?(\d+)\s*мин\))?$/gm;
213
+ let m: RegExpExecArray | null;
214
+ while ((m = re.exec(raw))) {
215
+ out.push({
216
+ id: slug(m[2]!) || `m${m[1]}`,
217
+ title: m[2]!,
218
+ objective: m[3] ?? "",
219
+ estMinutes: m[4] ? Number(m[4]) : 30,
220
+ });
221
+ }
222
+ return out;
223
+ }
224
+
225
+ function slug(s: string): string {
226
+ return s
227
+ .normalize("NFKD")
228
+ .toLowerCase()
229
+ .replace(/[^\p{L}\p{N}]+/gu, "-")
230
+ .replace(/^-+|-+$/g, "")
231
+ .slice(0, 60);
232
+ }
233
+
234
+ function baseSlug(rel: string): string {
235
+ return (rel.split("/").pop() ?? rel)
236
+ .replace(/\.md$/, "")
237
+ .replace(/^\d{4}-\d{2}-\d{2}-/, "");
238
+ }
239
+
240
+ export async function deleteCourse(courseId: string): Promise<void> {
241
+ // fs.delete isn't exposed yet; overwrite with empty marker for now.
242
+ // Listing skips entries that fail to parse so this effectively hides
243
+ // the course until a proper delete RPC ships.
244
+ await reflex.fs.write({
245
+ path: `${DIR}/${courseId}.json`,
246
+ content: "// deleted",
247
+ });
248
+ }