@agentick/core 0.0.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 (626) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +875 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/.tsbuildinfo.build +1 -0
  5. package/dist/agent.d.ts +32 -0
  6. package/dist/agent.d.ts.map +1 -0
  7. package/dist/agent.js +26 -0
  8. package/dist/agent.js.map +1 -0
  9. package/dist/agentick-instance.d.ts +285 -0
  10. package/dist/agentick-instance.d.ts.map +1 -0
  11. package/dist/agentick-instance.js +700 -0
  12. package/dist/agentick-instance.js.map +1 -0
  13. package/dist/aidk-instance.d.ts +294 -0
  14. package/dist/aidk-instance.d.ts.map +1 -0
  15. package/dist/aidk-instance.js +340 -0
  16. package/dist/aidk-instance.js.map +1 -0
  17. package/dist/app/session-store.d.ts +57 -0
  18. package/dist/app/session-store.d.ts.map +1 -0
  19. package/dist/app/session-store.js +87 -0
  20. package/dist/app/session-store.js.map +1 -0
  21. package/dist/app/session.d.ts +209 -0
  22. package/dist/app/session.d.ts.map +1 -0
  23. package/dist/app/session.js +2131 -0
  24. package/dist/app/session.js.map +1 -0
  25. package/dist/app/sqlite-session-store.d.ts +60 -0
  26. package/dist/app/sqlite-session-store.d.ts.map +1 -0
  27. package/dist/app/sqlite-session-store.js +234 -0
  28. package/dist/app/sqlite-session-store.js.map +1 -0
  29. package/dist/app/types.d.ts +1461 -0
  30. package/dist/app/types.d.ts.map +1 -0
  31. package/dist/app/types.js +14 -0
  32. package/dist/app/types.js.map +1 -0
  33. package/dist/app.d.ts +79 -0
  34. package/dist/app.d.ts.map +1 -0
  35. package/dist/app.js +83 -0
  36. package/dist/app.js.map +1 -0
  37. package/dist/channels/adapters/index.d.ts +2 -0
  38. package/dist/channels/adapters/index.d.ts.map +1 -0
  39. package/dist/channels/adapters/index.js +2 -0
  40. package/dist/channels/adapters/index.js.map +1 -0
  41. package/dist/channels/adapters/redis.d.ts +77 -0
  42. package/dist/channels/adapters/redis.d.ts.map +1 -0
  43. package/dist/channels/adapters/redis.js +259 -0
  44. package/dist/channels/adapters/redis.js.map +1 -0
  45. package/dist/channels/index.d.ts +38 -0
  46. package/dist/channels/index.d.ts.map +1 -0
  47. package/dist/channels/index.js +38 -0
  48. package/dist/channels/index.js.map +1 -0
  49. package/dist/channels/service.d.ts +684 -0
  50. package/dist/channels/service.d.ts.map +1 -0
  51. package/dist/channels/service.js +870 -0
  52. package/dist/channels/service.js.map +1 -0
  53. package/dist/channels/transports/index.d.ts +4 -0
  54. package/dist/channels/transports/index.d.ts.map +1 -0
  55. package/dist/channels/transports/index.js +4 -0
  56. package/dist/channels/transports/index.js.map +1 -0
  57. package/dist/channels/transports/socketio.d.ts +98 -0
  58. package/dist/channels/transports/socketio.d.ts.map +1 -0
  59. package/dist/channels/transports/socketio.js +246 -0
  60. package/dist/channels/transports/socketio.js.map +1 -0
  61. package/dist/channels/transports/streamable-http.d.ts +107 -0
  62. package/dist/channels/transports/streamable-http.d.ts.map +1 -0
  63. package/dist/channels/transports/streamable-http.js +353 -0
  64. package/dist/channels/transports/streamable-http.js.map +1 -0
  65. package/dist/channels/transports/websocket.d.ts +117 -0
  66. package/dist/channels/transports/websocket.d.ts.map +1 -0
  67. package/dist/channels/transports/websocket.js +416 -0
  68. package/dist/channels/transports/websocket.js.map +1 -0
  69. package/dist/com/index.d.ts +29 -0
  70. package/dist/com/index.d.ts.map +1 -0
  71. package/dist/com/index.js +29 -0
  72. package/dist/com/index.js.map +1 -0
  73. package/dist/com/object-model.d.ts +634 -0
  74. package/dist/com/object-model.d.ts.map +1 -0
  75. package/dist/com/object-model.js +963 -0
  76. package/dist/com/object-model.js.map +1 -0
  77. package/dist/com/types.d.ts +192 -0
  78. package/dist/com/types.d.ts.map +1 -0
  79. package/dist/com/types.js +1 -0
  80. package/dist/com/types.js.map +1 -0
  81. package/dist/compiler/collector.d.ts +16 -0
  82. package/dist/compiler/collector.d.ts.map +1 -0
  83. package/dist/compiler/collector.js +388 -0
  84. package/dist/compiler/collector.js.map +1 -0
  85. package/dist/compiler/content-block-registry.d.ts +11 -0
  86. package/dist/compiler/content-block-registry.d.ts.map +1 -0
  87. package/dist/compiler/content-block-registry.js +312 -0
  88. package/dist/compiler/content-block-registry.js.map +1 -0
  89. package/dist/compiler/extractors.d.ts +68 -0
  90. package/dist/compiler/extractors.d.ts.map +1 -0
  91. package/dist/compiler/extractors.js +547 -0
  92. package/dist/compiler/extractors.js.map +1 -0
  93. package/dist/compiler/fiber-compiler.d.ts +203 -0
  94. package/dist/compiler/fiber-compiler.d.ts.map +1 -0
  95. package/dist/compiler/fiber-compiler.js +498 -0
  96. package/dist/compiler/fiber-compiler.js.map +1 -0
  97. package/dist/compiler/fiber.d.ts +61 -0
  98. package/dist/compiler/fiber.d.ts.map +1 -0
  99. package/dist/compiler/fiber.js +244 -0
  100. package/dist/compiler/fiber.js.map +1 -0
  101. package/dist/compiler/index.d.ts +18 -0
  102. package/dist/compiler/index.d.ts.map +1 -0
  103. package/dist/compiler/index.js +38 -0
  104. package/dist/compiler/index.js.map +1 -0
  105. package/dist/compiler/scheduler.d.ts +95 -0
  106. package/dist/compiler/scheduler.d.ts.map +1 -0
  107. package/dist/compiler/scheduler.js +138 -0
  108. package/dist/compiler/scheduler.js.map +1 -0
  109. package/dist/compiler/structure-renderer.d.ts +42 -0
  110. package/dist/compiler/structure-renderer.d.ts.map +1 -0
  111. package/dist/compiler/structure-renderer.js +189 -0
  112. package/dist/compiler/structure-renderer.js.map +1 -0
  113. package/dist/compiler/types.d.ts +96 -0
  114. package/dist/compiler/types.d.ts.map +1 -0
  115. package/dist/compiler/types.js +19 -0
  116. package/dist/compiler/types.js.map +1 -0
  117. package/dist/component/component-hooks.d.ts +68 -0
  118. package/dist/component/component-hooks.d.ts.map +1 -0
  119. package/dist/component/component-hooks.js +112 -0
  120. package/dist/component/component-hooks.js.map +1 -0
  121. package/dist/component/component.d.ts +314 -0
  122. package/dist/component/component.d.ts.map +1 -0
  123. package/dist/component/component.js +64 -0
  124. package/dist/component/component.js.map +1 -0
  125. package/dist/component/index.d.ts +47 -0
  126. package/dist/component/index.d.ts.map +1 -0
  127. package/dist/component/index.js +47 -0
  128. package/dist/component/index.js.map +1 -0
  129. package/dist/component/tentickle-component.d.ts +185 -0
  130. package/dist/component/tentickle-component.d.ts.map +1 -0
  131. package/dist/component/tentickle-component.js +182 -0
  132. package/dist/component/tentickle-component.js.map +1 -0
  133. package/dist/content/index.d.ts +12 -0
  134. package/dist/content/index.d.ts.map +1 -0
  135. package/dist/content/index.js +17 -0
  136. package/dist/content/index.js.map +1 -0
  137. package/dist/context/index.d.ts +51 -0
  138. package/dist/context/index.d.ts.map +1 -0
  139. package/dist/context/index.js +69 -0
  140. package/dist/context/index.js.map +1 -0
  141. package/dist/core/channel-helpers.d.ts +31 -0
  142. package/dist/core/channel-helpers.d.ts.map +1 -0
  143. package/dist/core/channel-helpers.js +62 -0
  144. package/dist/core/channel-helpers.js.map +1 -0
  145. package/dist/core/channel.d.ts +164 -0
  146. package/dist/core/channel.d.ts.map +1 -0
  147. package/dist/core/channel.js +199 -0
  148. package/dist/core/channel.js.map +1 -0
  149. package/dist/core/context.d.ts +412 -0
  150. package/dist/core/context.d.ts.map +1 -0
  151. package/dist/core/context.js +290 -0
  152. package/dist/core/context.js.map +1 -0
  153. package/dist/core/event-buffer.d.ts +212 -0
  154. package/dist/core/event-buffer.d.ts.map +1 -0
  155. package/dist/core/event-buffer.js +346 -0
  156. package/dist/core/event-buffer.js.map +1 -0
  157. package/dist/core/execution-helpers.d.ts +179 -0
  158. package/dist/core/execution-helpers.d.ts.map +1 -0
  159. package/dist/core/execution-helpers.js +212 -0
  160. package/dist/core/execution-helpers.js.map +1 -0
  161. package/dist/core/execution-tracker.d.ts +53 -0
  162. package/dist/core/execution-tracker.d.ts.map +1 -0
  163. package/dist/core/execution-tracker.js +309 -0
  164. package/dist/core/execution-tracker.js.map +1 -0
  165. package/dist/core/index.d.ts +58 -0
  166. package/dist/core/index.d.ts.map +1 -0
  167. package/dist/core/index.js +58 -0
  168. package/dist/core/index.js.map +1 -0
  169. package/dist/core/logger.d.ts +341 -0
  170. package/dist/core/logger.d.ts.map +1 -0
  171. package/dist/core/logger.js +346 -0
  172. package/dist/core/logger.js.map +1 -0
  173. package/dist/core/metrics-helpers.d.ts +40 -0
  174. package/dist/core/metrics-helpers.d.ts.map +1 -0
  175. package/dist/core/metrics-helpers.js +72 -0
  176. package/dist/core/metrics-helpers.js.map +1 -0
  177. package/dist/core/otel-provider.d.ts +54 -0
  178. package/dist/core/otel-provider.d.ts.map +1 -0
  179. package/dist/core/otel-provider.js +107 -0
  180. package/dist/core/otel-provider.js.map +1 -0
  181. package/dist/core/procedure-graph.d.ts +136 -0
  182. package/dist/core/procedure-graph.d.ts.map +1 -0
  183. package/dist/core/procedure-graph.js +272 -0
  184. package/dist/core/procedure-graph.js.map +1 -0
  185. package/dist/core/procedure.d.ts +755 -0
  186. package/dist/core/procedure.d.ts.map +1 -0
  187. package/dist/core/procedure.js +899 -0
  188. package/dist/core/procedure.js.map +1 -0
  189. package/dist/core/stream.d.ts +106 -0
  190. package/dist/core/stream.d.ts.map +1 -0
  191. package/dist/core/stream.js +186 -0
  192. package/dist/core/stream.js.map +1 -0
  193. package/dist/core/telemetry.d.ts +182 -0
  194. package/dist/core/telemetry.d.ts.map +1 -0
  195. package/dist/core/telemetry.js +124 -0
  196. package/dist/core/telemetry.js.map +1 -0
  197. package/dist/engine/client-tool-coordinator.d.ts +50 -0
  198. package/dist/engine/client-tool-coordinator.d.ts.map +1 -0
  199. package/dist/engine/client-tool-coordinator.js +121 -0
  200. package/dist/engine/client-tool-coordinator.js.map +1 -0
  201. package/dist/engine/engine-events.d.ts +117 -0
  202. package/dist/engine/engine-events.d.ts.map +1 -0
  203. package/dist/engine/engine-events.js +178 -0
  204. package/dist/engine/engine-events.js.map +1 -0
  205. package/dist/engine/engine-response.d.ts +48 -0
  206. package/dist/engine/engine-response.d.ts.map +1 -0
  207. package/dist/engine/engine-response.js +2 -0
  208. package/dist/engine/engine-response.js.map +1 -0
  209. package/dist/engine/execution-graph.d.ts +104 -0
  210. package/dist/engine/execution-graph.d.ts.map +1 -0
  211. package/dist/engine/execution-graph.js +257 -0
  212. package/dist/engine/execution-graph.js.map +1 -0
  213. package/dist/engine/execution-handle.d.ts +212 -0
  214. package/dist/engine/execution-handle.d.ts.map +1 -0
  215. package/dist/engine/execution-handle.js +602 -0
  216. package/dist/engine/execution-handle.js.map +1 -0
  217. package/dist/engine/execution-types.d.ts +248 -0
  218. package/dist/engine/execution-types.d.ts.map +1 -0
  219. package/dist/engine/execution-types.js +23 -0
  220. package/dist/engine/execution-types.js.map +1 -0
  221. package/dist/engine/index.d.ts +21 -0
  222. package/dist/engine/index.d.ts.map +1 -0
  223. package/dist/engine/index.js +23 -0
  224. package/dist/engine/index.js.map +1 -0
  225. package/dist/engine/tool-confirmation-coordinator.d.ts +74 -0
  226. package/dist/engine/tool-confirmation-coordinator.d.ts.map +1 -0
  227. package/dist/engine/tool-confirmation-coordinator.js +137 -0
  228. package/dist/engine/tool-confirmation-coordinator.js.map +1 -0
  229. package/dist/engine/tool-executor.d.ts +127 -0
  230. package/dist/engine/tool-executor.d.ts.map +1 -0
  231. package/dist/engine/tool-executor.js +363 -0
  232. package/dist/engine/tool-executor.js.map +1 -0
  233. package/dist/hibernation/index.d.ts +126 -0
  234. package/dist/hibernation/index.d.ts.map +1 -0
  235. package/dist/hibernation/index.js +127 -0
  236. package/dist/hibernation/index.js.map +1 -0
  237. package/dist/hooks/base-hook-registry.d.ts +41 -0
  238. package/dist/hooks/base-hook-registry.d.ts.map +1 -0
  239. package/dist/hooks/base-hook-registry.js +76 -0
  240. package/dist/hooks/base-hook-registry.js.map +1 -0
  241. package/dist/hooks/com-state.d.ts +40 -0
  242. package/dist/hooks/com-state.d.ts.map +1 -0
  243. package/dist/hooks/com-state.js +90 -0
  244. package/dist/hooks/com-state.js.map +1 -0
  245. package/dist/hooks/context-info.d.ts +139 -0
  246. package/dist/hooks/context-info.d.ts.map +1 -0
  247. package/dist/hooks/context-info.js +115 -0
  248. package/dist/hooks/context-info.js.map +1 -0
  249. package/dist/hooks/context-internal.d.ts +21 -0
  250. package/dist/hooks/context-internal.d.ts.map +1 -0
  251. package/dist/hooks/context-internal.js +20 -0
  252. package/dist/hooks/context-internal.js.map +1 -0
  253. package/dist/hooks/context.d.ts +64 -0
  254. package/dist/hooks/context.d.ts.map +1 -0
  255. package/dist/hooks/context.js +83 -0
  256. package/dist/hooks/context.js.map +1 -0
  257. package/dist/hooks/data.d.ts +33 -0
  258. package/dist/hooks/data.d.ts.map +1 -0
  259. package/dist/hooks/data.js +84 -0
  260. package/dist/hooks/data.js.map +1 -0
  261. package/dist/hooks/formatter-context.d.ts +34 -0
  262. package/dist/hooks/formatter-context.d.ts.map +1 -0
  263. package/dist/hooks/formatter-context.js +34 -0
  264. package/dist/hooks/formatter-context.js.map +1 -0
  265. package/dist/hooks/hook-registry.d.ts +45 -0
  266. package/dist/hooks/hook-registry.d.ts.map +1 -0
  267. package/dist/hooks/hook-registry.js +109 -0
  268. package/dist/hooks/hook-registry.js.map +1 -0
  269. package/dist/hooks/index.d.ts +20 -0
  270. package/dist/hooks/index.d.ts.map +1 -0
  271. package/dist/hooks/index.js +47 -0
  272. package/dist/hooks/index.js.map +1 -0
  273. package/dist/hooks/knob.d.ts +87 -0
  274. package/dist/hooks/knob.d.ts.map +1 -0
  275. package/dist/hooks/knob.js +129 -0
  276. package/dist/hooks/knob.js.map +1 -0
  277. package/dist/hooks/knobs-component.d.ts +70 -0
  278. package/dist/hooks/knobs-component.d.ts.map +1 -0
  279. package/dist/hooks/knobs-component.js +300 -0
  280. package/dist/hooks/knobs-component.js.map +1 -0
  281. package/dist/hooks/lifecycle.d.ts +158 -0
  282. package/dist/hooks/lifecycle.d.ts.map +1 -0
  283. package/dist/hooks/lifecycle.js +217 -0
  284. package/dist/hooks/lifecycle.js.map +1 -0
  285. package/dist/hooks/message-context.d.ts +101 -0
  286. package/dist/hooks/message-context.d.ts.map +1 -0
  287. package/dist/hooks/message-context.js +145 -0
  288. package/dist/hooks/message-context.js.map +1 -0
  289. package/dist/hooks/policy-context.d.ts.map +1 -0
  290. package/dist/hooks/runtime-context.d.ts +122 -0
  291. package/dist/hooks/runtime-context.d.ts.map +1 -0
  292. package/dist/hooks/runtime-context.js +149 -0
  293. package/dist/hooks/runtime-context.js.map +1 -0
  294. package/dist/hooks/signal.d.ts +267 -0
  295. package/dist/hooks/signal.d.ts.map +1 -0
  296. package/dist/hooks/signal.js +825 -0
  297. package/dist/hooks/signal.js.map +1 -0
  298. package/dist/hooks/types.d.ts +179 -0
  299. package/dist/hooks/types.d.ts.map +1 -0
  300. package/dist/hooks/types.js +5 -0
  301. package/dist/hooks/types.js.map +1 -0
  302. package/dist/index.d.ts +20 -0
  303. package/dist/index.d.ts.map +1 -0
  304. package/dist/index.js +50 -0
  305. package/dist/index.js.map +1 -0
  306. package/dist/jsx/components/agent.d.ts +64 -0
  307. package/dist/jsx/components/agent.d.ts.map +1 -0
  308. package/dist/jsx/components/agent.js +80 -0
  309. package/dist/jsx/components/agent.js.map +1 -0
  310. package/dist/jsx/components/complete.d.ts +65 -0
  311. package/dist/jsx/components/complete.d.ts.map +1 -0
  312. package/dist/jsx/components/complete.js +64 -0
  313. package/dist/jsx/components/complete.js.map +1 -0
  314. package/dist/jsx/components/content.d.ts +98 -0
  315. package/dist/jsx/components/content.d.ts.map +1 -0
  316. package/dist/jsx/components/content.js +51 -0
  317. package/dist/jsx/components/content.js.map +1 -0
  318. package/dist/jsx/components/harness.d.ts +118 -0
  319. package/dist/jsx/components/harness.d.ts.map +1 -0
  320. package/dist/jsx/components/harness.js +117 -0
  321. package/dist/jsx/components/harness.js.map +1 -0
  322. package/dist/jsx/components/index.d.ts +11 -0
  323. package/dist/jsx/components/index.d.ts.map +1 -0
  324. package/dist/jsx/components/index.js +11 -0
  325. package/dist/jsx/components/index.js.map +1 -0
  326. package/dist/jsx/components/markdown.d.ts +31 -0
  327. package/dist/jsx/components/markdown.d.ts.map +1 -0
  328. package/dist/jsx/components/markdown.js +17 -0
  329. package/dist/jsx/components/markdown.js.map +1 -0
  330. package/dist/jsx/components/messages.d.ts +283 -0
  331. package/dist/jsx/components/messages.d.ts.map +1 -0
  332. package/dist/jsx/components/messages.js +257 -0
  333. package/dist/jsx/components/messages.js.map +1 -0
  334. package/dist/jsx/components/model.d.ts +94 -0
  335. package/dist/jsx/components/model.d.ts.map +1 -0
  336. package/dist/jsx/components/model.js +96 -0
  337. package/dist/jsx/components/model.js.map +1 -0
  338. package/dist/jsx/components/primitives.d.ts +117 -0
  339. package/dist/jsx/components/primitives.d.ts.map +1 -0
  340. package/dist/jsx/components/primitives.js +83 -0
  341. package/dist/jsx/components/primitives.js.map +1 -0
  342. package/dist/jsx/components/renderer.d.ts +24 -0
  343. package/dist/jsx/components/renderer.d.ts.map +1 -0
  344. package/dist/jsx/components/renderer.js +11 -0
  345. package/dist/jsx/components/renderer.js.map +1 -0
  346. package/dist/jsx/components/semantic.d.ts +155 -0
  347. package/dist/jsx/components/semantic.d.ts.map +1 -0
  348. package/dist/jsx/components/semantic.js +39 -0
  349. package/dist/jsx/components/semantic.js.map +1 -0
  350. package/dist/jsx/components/timeline.d.ts +157 -0
  351. package/dist/jsx/components/timeline.d.ts.map +1 -0
  352. package/dist/jsx/components/timeline.js +357 -0
  353. package/dist/jsx/components/timeline.js.map +1 -0
  354. package/dist/jsx/components/token-budget.d.ts +70 -0
  355. package/dist/jsx/components/token-budget.d.ts.map +1 -0
  356. package/dist/jsx/components/token-budget.js +135 -0
  357. package/dist/jsx/components/token-budget.js.map +1 -0
  358. package/dist/jsx/components/xml.d.ts +27 -0
  359. package/dist/jsx/components/xml.d.ts.map +1 -0
  360. package/dist/jsx/components/xml.js +17 -0
  361. package/dist/jsx/components/xml.js.map +1 -0
  362. package/dist/jsx/index.d.ts +58 -0
  363. package/dist/jsx/index.d.ts.map +1 -0
  364. package/dist/jsx/index.js +59 -0
  365. package/dist/jsx/index.js.map +1 -0
  366. package/dist/jsx/jsx-runtime.d.ts +370 -0
  367. package/dist/jsx/jsx-runtime.d.ts.map +1 -0
  368. package/dist/jsx/jsx-runtime.js +79 -0
  369. package/dist/jsx/jsx-runtime.js.map +1 -0
  370. package/dist/jsx/jsx-types.d.ts +23 -0
  371. package/dist/jsx/jsx-types.d.ts.map +1 -0
  372. package/dist/jsx/jsx-types.js +1 -0
  373. package/dist/jsx/jsx-types.js.map +1 -0
  374. package/dist/mcp/client.d.ts +46 -0
  375. package/dist/mcp/client.d.ts.map +1 -0
  376. package/dist/mcp/client.js +138 -0
  377. package/dist/mcp/client.js.map +1 -0
  378. package/dist/mcp/component.d.ts +95 -0
  379. package/dist/mcp/component.d.ts.map +1 -0
  380. package/dist/mcp/component.js +185 -0
  381. package/dist/mcp/component.js.map +1 -0
  382. package/dist/mcp/create-mcp-tool.d.ts +191 -0
  383. package/dist/mcp/create-mcp-tool.d.ts.map +1 -0
  384. package/dist/mcp/create-mcp-tool.js +228 -0
  385. package/dist/mcp/create-mcp-tool.js.map +1 -0
  386. package/dist/mcp/index.d.ts +49 -0
  387. package/dist/mcp/index.d.ts.map +1 -0
  388. package/dist/mcp/index.js +48 -0
  389. package/dist/mcp/index.js.map +1 -0
  390. package/dist/mcp/service.d.ts +39 -0
  391. package/dist/mcp/service.d.ts.map +1 -0
  392. package/dist/mcp/service.js +77 -0
  393. package/dist/mcp/service.js.map +1 -0
  394. package/dist/mcp/tool.d.ts +55 -0
  395. package/dist/mcp/tool.d.ts.map +1 -0
  396. package/dist/mcp/tool.js +119 -0
  397. package/dist/mcp/tool.js.map +1 -0
  398. package/dist/mcp/types.d.ts +72 -0
  399. package/dist/mcp/types.d.ts.map +1 -0
  400. package/dist/mcp/types.js +6 -0
  401. package/dist/mcp/types.js.map +1 -0
  402. package/dist/middleware/defaults.d.ts +9 -0
  403. package/dist/middleware/defaults.d.ts.map +1 -0
  404. package/dist/middleware/defaults.js +47 -0
  405. package/dist/middleware/defaults.js.map +1 -0
  406. package/dist/model/adapter-helpers.d.ts +161 -0
  407. package/dist/model/adapter-helpers.d.ts.map +1 -0
  408. package/dist/model/adapter-helpers.js +351 -0
  409. package/dist/model/adapter-helpers.js.map +1 -0
  410. package/dist/model/adapter.d.ts +399 -0
  411. package/dist/model/adapter.d.ts.map +1 -0
  412. package/dist/model/adapter.js +497 -0
  413. package/dist/model/adapter.js.map +1 -0
  414. package/dist/model/index.d.ts +54 -0
  415. package/dist/model/index.d.ts.map +1 -0
  416. package/dist/model/index.js +55 -0
  417. package/dist/model/index.js.map +1 -0
  418. package/dist/model/model-hooks.d.ts +45 -0
  419. package/dist/model/model-hooks.d.ts.map +1 -0
  420. package/dist/model/model-hooks.js +24 -0
  421. package/dist/model/model-hooks.js.map +1 -0
  422. package/dist/model/model.d.ts +302 -0
  423. package/dist/model/model.d.ts.map +1 -0
  424. package/dist/model/model.js +20 -0
  425. package/dist/model/model.js.map +1 -0
  426. package/dist/model/simple-adapter.d.ts +176 -0
  427. package/dist/model/simple-adapter.d.ts.map +1 -0
  428. package/dist/model/simple-adapter.js +264 -0
  429. package/dist/model/simple-adapter.js.map +1 -0
  430. package/dist/model/stream-accumulator.d.ts +284 -0
  431. package/dist/model/stream-accumulator.d.ts.map +1 -0
  432. package/dist/model/stream-accumulator.js +532 -0
  433. package/dist/model/stream-accumulator.js.map +1 -0
  434. package/dist/model/utils/index.d.ts +2 -0
  435. package/dist/model/utils/index.d.ts.map +1 -0
  436. package/dist/model/utils/index.js +2 -0
  437. package/dist/model/utils/index.js.map +1 -0
  438. package/dist/model/utils/language-model.d.ts +26 -0
  439. package/dist/model/utils/language-model.d.ts.map +1 -0
  440. package/dist/model/utils/language-model.js +706 -0
  441. package/dist/model/utils/language-model.js.map +1 -0
  442. package/dist/procedure/index.d.ts +20 -0
  443. package/dist/procedure/index.d.ts.map +1 -0
  444. package/dist/procedure/index.js +19 -0
  445. package/dist/procedure/index.js.map +1 -0
  446. package/dist/reconciler/devtools-bridge.d.ts +40 -0
  447. package/dist/reconciler/devtools-bridge.d.ts.map +1 -0
  448. package/dist/reconciler/devtools-bridge.js +79 -0
  449. package/dist/reconciler/devtools-bridge.js.map +1 -0
  450. package/dist/reconciler/host-config.d.ts +39 -0
  451. package/dist/reconciler/host-config.d.ts.map +1 -0
  452. package/dist/reconciler/host-config.js +195 -0
  453. package/dist/reconciler/host-config.js.map +1 -0
  454. package/dist/reconciler/index.d.ts +7 -0
  455. package/dist/reconciler/index.d.ts.map +1 -0
  456. package/dist/reconciler/index.js +7 -0
  457. package/dist/reconciler/index.js.map +1 -0
  458. package/dist/reconciler/reconciler.d.ts +47 -0
  459. package/dist/reconciler/reconciler.d.ts.map +1 -0
  460. package/dist/reconciler/reconciler.js +89 -0
  461. package/dist/reconciler/reconciler.js.map +1 -0
  462. package/dist/reconciler/types.d.ts +86 -0
  463. package/dist/reconciler/types.d.ts.map +1 -0
  464. package/dist/reconciler/types.js +37 -0
  465. package/dist/reconciler/types.js.map +1 -0
  466. package/dist/renderers/base.d.ts +98 -0
  467. package/dist/renderers/base.d.ts.map +1 -0
  468. package/dist/renderers/base.js +82 -0
  469. package/dist/renderers/base.js.map +1 -0
  470. package/dist/renderers/index.d.ts +31 -0
  471. package/dist/renderers/index.d.ts.map +1 -0
  472. package/dist/renderers/index.js +31 -0
  473. package/dist/renderers/index.js.map +1 -0
  474. package/dist/renderers/markdown.d.ts +48 -0
  475. package/dist/renderers/markdown.d.ts.map +1 -0
  476. package/dist/renderers/markdown.js +432 -0
  477. package/dist/renderers/markdown.js.map +1 -0
  478. package/dist/renderers/types.d.ts +7 -0
  479. package/dist/renderers/types.d.ts.map +1 -0
  480. package/dist/renderers/types.js +7 -0
  481. package/dist/renderers/types.js.map +1 -0
  482. package/dist/renderers/xml.d.ts +49 -0
  483. package/dist/renderers/xml.d.ts.map +1 -0
  484. package/dist/renderers/xml.js +444 -0
  485. package/dist/renderers/xml.js.map +1 -0
  486. package/dist/state/boundary.d.ts +347 -0
  487. package/dist/state/boundary.d.ts.map +1 -0
  488. package/dist/state/boundary.js +341 -0
  489. package/dist/state/boundary.js.map +1 -0
  490. package/dist/state/context.d.ts +138 -0
  491. package/dist/state/context.d.ts.map +1 -0
  492. package/dist/state/context.js +139 -0
  493. package/dist/state/context.js.map +1 -0
  494. package/dist/state/hooks.d.ts +798 -0
  495. package/dist/state/hooks.d.ts.map +1 -0
  496. package/dist/state/hooks.js +1437 -0
  497. package/dist/state/hooks.js.map +1 -0
  498. package/dist/state/index.d.ts +72 -0
  499. package/dist/state/index.d.ts.map +1 -0
  500. package/dist/state/index.js +73 -0
  501. package/dist/state/index.js.map +1 -0
  502. package/dist/state/signal.d.ts +223 -0
  503. package/dist/state/signal.d.ts.map +1 -0
  504. package/dist/state/signal.js +699 -0
  505. package/dist/state/signal.js.map +1 -0
  506. package/dist/state/use-state.d.ts +210 -0
  507. package/dist/state/use-state.d.ts.map +1 -0
  508. package/dist/state/use-state.js +327 -0
  509. package/dist/state/use-state.js.map +1 -0
  510. package/dist/tentickle-instance.d.ts +285 -0
  511. package/dist/tentickle-instance.d.ts.map +1 -0
  512. package/dist/tentickle-instance.js +700 -0
  513. package/dist/tentickle-instance.js.map +1 -0
  514. package/dist/testing/act.d.ts +59 -0
  515. package/dist/testing/act.d.ts.map +1 -0
  516. package/dist/testing/act.js +92 -0
  517. package/dist/testing/act.js.map +1 -0
  518. package/dist/testing/async-helpers.d.ts +99 -0
  519. package/dist/testing/async-helpers.d.ts.map +1 -0
  520. package/dist/testing/async-helpers.js +193 -0
  521. package/dist/testing/async-helpers.js.map +1 -0
  522. package/dist/testing/compile-agent.d.ts +101 -0
  523. package/dist/testing/compile-agent.d.ts.map +1 -0
  524. package/dist/testing/compile-agent.js +136 -0
  525. package/dist/testing/compile-agent.js.map +1 -0
  526. package/dist/testing/index.d.ts +57 -0
  527. package/dist/testing/index.d.ts.map +1 -0
  528. package/dist/testing/index.js +59 -0
  529. package/dist/testing/index.js.map +1 -0
  530. package/dist/testing/mock-app.d.ts +163 -0
  531. package/dist/testing/mock-app.d.ts.map +1 -0
  532. package/dist/testing/mock-app.js +393 -0
  533. package/dist/testing/mock-app.js.map +1 -0
  534. package/dist/testing/mocks.d.ts +142 -0
  535. package/dist/testing/mocks.d.ts.map +1 -0
  536. package/dist/testing/mocks.js +191 -0
  537. package/dist/testing/mocks.js.map +1 -0
  538. package/dist/testing/render-agent.d.ts +146 -0
  539. package/dist/testing/render-agent.d.ts.map +1 -0
  540. package/dist/testing/render-agent.js +200 -0
  541. package/dist/testing/render-agent.js.map +1 -0
  542. package/dist/testing/test-adapter.d.ts +157 -0
  543. package/dist/testing/test-adapter.d.ts.map +1 -0
  544. package/dist/testing/test-adapter.js +297 -0
  545. package/dist/testing/test-adapter.js.map +1 -0
  546. package/dist/testing/test-model.d.ts +132 -0
  547. package/dist/testing/test-model.d.ts.map +1 -0
  548. package/dist/testing/test-model.js +260 -0
  549. package/dist/testing/test-model.js.map +1 -0
  550. package/dist/tool/index.d.ts +61 -0
  551. package/dist/tool/index.d.ts.map +1 -0
  552. package/dist/tool/index.js +63 -0
  553. package/dist/tool/index.js.map +1 -0
  554. package/dist/tool/tool-hooks.d.ts +45 -0
  555. package/dist/tool/tool-hooks.d.ts.map +1 -0
  556. package/dist/tool/tool-hooks.js +35 -0
  557. package/dist/tool/tool-hooks.js.map +1 -0
  558. package/dist/tool/tool.d.ts +403 -0
  559. package/dist/tool/tool.d.ts.map +1 -0
  560. package/dist/tool/tool.js +176 -0
  561. package/dist/tool/tool.js.map +1 -0
  562. package/dist/types.d.ts +442 -0
  563. package/dist/types.d.ts.map +1 -0
  564. package/dist/types.js +97 -0
  565. package/dist/types.js.map +1 -0
  566. package/dist/utils/abort-utils.d.ts +5 -0
  567. package/dist/utils/abort-utils.d.ts.map +1 -0
  568. package/dist/utils/abort-utils.js +50 -0
  569. package/dist/utils/abort-utils.js.map +1 -0
  570. package/dist/utils/classify-error.d.ts +19 -0
  571. package/dist/utils/classify-error.d.ts.map +1 -0
  572. package/dist/utils/classify-error.js +77 -0
  573. package/dist/utils/classify-error.js.map +1 -0
  574. package/dist/utils/index.d.ts +21 -0
  575. package/dist/utils/index.d.ts.map +1 -0
  576. package/dist/utils/index.js +21 -0
  577. package/dist/utils/index.js.map +1 -0
  578. package/dist/utils/normalization.d.ts +6 -0
  579. package/dist/utils/normalization.d.ts.map +1 -0
  580. package/dist/utils/normalization.js +103 -0
  581. package/dist/utils/normalization.js.map +1 -0
  582. package/dist/utils/registry.d.ts +15 -0
  583. package/dist/utils/registry.d.ts.map +1 -0
  584. package/dist/utils/registry.js +28 -0
  585. package/dist/utils/registry.js.map +1 -0
  586. package/dist/utils/schema.d.ts +7 -0
  587. package/dist/utils/schema.d.ts.map +1 -0
  588. package/dist/utils/schema.js +13 -0
  589. package/dist/utils/schema.js.map +1 -0
  590. package/dist/utils/token-estimate.d.ts +87 -0
  591. package/dist/utils/token-estimate.d.ts.map +1 -0
  592. package/dist/utils/token-estimate.js +199 -0
  593. package/dist/utils/token-estimate.js.map +1 -0
  594. package/dist/v2/reconciler/host-config.d.ts +31 -0
  595. package/dist/v2/reconciler/host-config.d.ts.map +1 -0
  596. package/dist/v2/reconciler/host-config.js +197 -0
  597. package/dist/v2/reconciler/host-config.js.map +1 -0
  598. package/dist/v2/reconciler/index.d.ts +7 -0
  599. package/dist/v2/reconciler/index.d.ts.map +1 -0
  600. package/dist/v2/reconciler/index.js +7 -0
  601. package/dist/v2/reconciler/index.js.map +1 -0
  602. package/dist/v2/reconciler/reconciler.d.ts +39 -0
  603. package/dist/v2/reconciler/reconciler.d.ts.map +1 -0
  604. package/dist/v2/reconciler/reconciler.js +54 -0
  605. package/dist/v2/reconciler/reconciler.js.map +1 -0
  606. package/dist/v2/reconciler/types.d.ts +64 -0
  607. package/dist/v2/reconciler/types.d.ts.map +1 -0
  608. package/dist/v2/reconciler/types.js +20 -0
  609. package/dist/v2/reconciler/types.js.map +1 -0
  610. package/dist/v2/renderers/index.d.ts +7 -0
  611. package/dist/v2/renderers/index.d.ts.map +1 -0
  612. package/dist/v2/renderers/index.js +7 -0
  613. package/dist/v2/renderers/index.js.map +1 -0
  614. package/dist/v2/renderers/markdown.d.ts +16 -0
  615. package/dist/v2/renderers/markdown.d.ts.map +1 -0
  616. package/dist/v2/renderers/markdown.js +65 -0
  617. package/dist/v2/renderers/markdown.js.map +1 -0
  618. package/dist/v2/renderers/types.d.ts +26 -0
  619. package/dist/v2/renderers/types.d.ts.map +1 -0
  620. package/dist/v2/renderers/types.js +6 -0
  621. package/dist/v2/renderers/types.js.map +1 -0
  622. package/dist/v2/renderers/xml.d.ts +17 -0
  623. package/dist/v2/renderers/xml.d.ts.map +1 -0
  624. package/dist/v2/renderers/xml.js +73 -0
  625. package/dist/v2/renderers/xml.js.map +1 -0
  626. package/package.json +49 -0
@@ -0,0 +1,1437 @@
1
+ /**
2
+ * V2 Hooks Implementation
3
+ *
4
+ * React-inspired hooks for function components in the tick-based agent model.
5
+ * Key difference from React: async-first, effects can be async.
6
+ *
7
+ * Rules of Hooks:
8
+ * 1. Only call hooks at the top level of a function component
9
+ * 2. Only call hooks from function components or custom hooks
10
+ * 3. Call hooks in the same order every render
11
+ */
12
+ import { HookTag, EffectPhase } from "../compiler/types";
13
+ import { signal as createSignal, computed, createCOMStateSignal, createReadonlyCOMStateSignal, isSignal, isComputed, } from "./signal";
14
+ import { shouldSkipRecompile } from "../compiler/fiber-compiler";
15
+ import { Logger } from "../core/logger";
16
+ const log = Logger.for("hooks");
17
+ // ============================================================================
18
+ // Render Context (Global During Render)
19
+ // ============================================================================
20
+ let renderContext = null;
21
+ /**
22
+ * Get current render context. Throws if called outside render.
23
+ */
24
+ export function getCurrentContext() {
25
+ if (renderContext === null) {
26
+ throw new Error("Invalid hook call. Hooks can only be called inside a function component.\n" +
27
+ "Possible causes:\n" +
28
+ "1. Calling a hook outside a component\n" +
29
+ "2. Calling hooks conditionally or in a loop\n" +
30
+ "3. Mismatched tentickle package versions");
31
+ }
32
+ return renderContext;
33
+ }
34
+ /**
35
+ * Set render context (called by compiler).
36
+ */
37
+ export function setRenderContext(ctx) {
38
+ renderContext = ctx;
39
+ }
40
+ /**
41
+ * Get current fiber (for advanced use).
42
+ */
43
+ export function getCurrentFiber() {
44
+ return renderContext?.fiber ?? null;
45
+ }
46
+ // ============================================================================
47
+ // Context Access Hooks
48
+ // ============================================================================
49
+ /**
50
+ * Get the COM (Context Object Model) for the current render.
51
+ *
52
+ * Use this instead of receiving COM as a component parameter.
53
+ * This makes components have standard React-like signatures: `(props) => JSX.Element`
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * // Before (legacy pattern with magic args):
58
+ * const MyComponent = (props, com, state) => { ... };
59
+ *
60
+ * // After (recommended hook pattern):
61
+ * const MyComponent = (props) => {
62
+ * const com = useCom();
63
+ * const state = useTickState();
64
+ * // ...
65
+ * };
66
+ * ```
67
+ */
68
+ export function useCom() {
69
+ return getCurrentContext().com;
70
+ }
71
+ /**
72
+ * Get the TickState for the current render.
73
+ *
74
+ * TickState contains:
75
+ * - `tick`: Current tick number (1-indexed)
76
+ * - `previous`: COMInput from previous tick (conversation history)
77
+ * - `current`: COMOutput from current tick (model response)
78
+ * - `stop(reason)`: Function to stop execution
79
+ * - `queuedMessages`: Messages received during execution
80
+ *
81
+ * @example
82
+ * ```tsx
83
+ * const MyComponent = (props) => {
84
+ * const state = useTickState();
85
+ * console.log(`Tick ${state.tick}`);
86
+ * // Access previous conversation via state.previous?.timeline
87
+ * };
88
+ * ```
89
+ */
90
+ export function useTickState() {
91
+ return getCurrentContext().tickState;
92
+ }
93
+ // ============================================================================
94
+ // Work Scheduling
95
+ // ============================================================================
96
+ /**
97
+ * Schedule work for a fiber using the scheduler from the current render context.
98
+ * This ensures concurrent compilations don't interfere with each other.
99
+ */
100
+ // function scheduleWork(fiber: FiberNode): void {
101
+ // // During render, we have renderContext available with the correct scheduler
102
+ // const ctx = renderContext;
103
+ // if (ctx?.scheduleWork) {
104
+ // ctx.scheduleWork(fiber);
105
+ // }
106
+ // }
107
+ // ============================================================================
108
+ // Hook State Management
109
+ // ============================================================================
110
+ /**
111
+ * Mount a new hook during initial render.
112
+ * If hydrating, attempts to restore state from hydration data.
113
+ */
114
+ function mountWorkInProgressHook() {
115
+ const ctx = getCurrentContext();
116
+ // Track hook index for hydration
117
+ const hookIndex = ctx.hookIndex ?? 0;
118
+ ctx.hookIndex = hookIndex + 1;
119
+ const hook = {
120
+ memoizedState: undefined,
121
+ queue: null,
122
+ effect: null,
123
+ next: null,
124
+ tag: HookTag.State,
125
+ };
126
+ // Check for hydration data
127
+ if (ctx.isHydrating && ctx.hydrationData?.hooks) {
128
+ const hydrationHook = ctx.hydrationData.hooks[hookIndex];
129
+ if (hydrationHook) {
130
+ // Restore memoized state from hydration
131
+ hook.memoizedState = hydrationHook.value;
132
+ }
133
+ }
134
+ if (ctx.workInProgressHook === null) {
135
+ ctx.fiber.memoizedState = hook;
136
+ }
137
+ else {
138
+ ctx.workInProgressHook.next = hook;
139
+ }
140
+ ctx.workInProgressHook = hook;
141
+ return hook;
142
+ }
143
+ /**
144
+ * Check if a hook should skip initialization because it's being hydrated.
145
+ * Returns the hydrated value if available.
146
+ */
147
+ // function getHydratedValue<T>(hookIndex: number): T | undefined {
148
+ // const ctx = getCurrentContext();
149
+ // if (ctx.isHydrating && ctx.hydrationData?.hooks) {
150
+ // const hydrationHook = ctx.hydrationData.hooks[hookIndex];
151
+ // if (hydrationHook) {
152
+ // return hydrationHook.value as T;
153
+ // }
154
+ // }
155
+ // return undefined;
156
+ // }
157
+ function updateWorkInProgressHook() {
158
+ const ctx = getCurrentContext();
159
+ const current = ctx.currentHook;
160
+ if (current === null) {
161
+ throw new Error("Rendered more hooks than during the previous render. " +
162
+ "Hooks must be called in the same order every render.");
163
+ }
164
+ const newHook = {
165
+ memoizedState: current.memoizedState,
166
+ baseState: current.baseState,
167
+ queue: current.queue,
168
+ effect: current.effect,
169
+ next: null,
170
+ tag: current.tag,
171
+ };
172
+ if (ctx.workInProgressHook === null) {
173
+ ctx.fiber.memoizedState = newHook;
174
+ }
175
+ else {
176
+ ctx.workInProgressHook.next = newHook;
177
+ }
178
+ ctx.workInProgressHook = newHook;
179
+ ctx.currentHook = current.next;
180
+ return newHook;
181
+ }
182
+ function mountOrUpdateHook(tag) {
183
+ const ctx = getCurrentContext();
184
+ const isMount = ctx.currentHook === null && ctx.fiber.alternate === null;
185
+ const hook = isMount ? mountWorkInProgressHook() : updateWorkInProgressHook();
186
+ hook.tag = tag;
187
+ return hook;
188
+ }
189
+ /**
190
+ * Extract signal values for dependency comparison.
191
+ * Signals/computed values are unwrapped to their current value.
192
+ */
193
+ function unwrapDeps(deps) {
194
+ if (!deps)
195
+ return deps;
196
+ return deps.map((dep) => {
197
+ // If it's a signal or computed, read its current value
198
+ if (isSignal(dep) || isComputed(dep)) {
199
+ return dep();
200
+ }
201
+ return dep;
202
+ });
203
+ }
204
+ // ============================================================================
205
+ // STATE HOOKS
206
+ // ============================================================================
207
+ /**
208
+ * useState - Local component state.
209
+ *
210
+ * State persists across renders via fiber storage.
211
+ *
212
+ * @example
213
+ * ```tsx
214
+ * // Old (deprecated):
215
+ * const [count, setCount] = useState(0);
216
+ *
217
+ * // New (recommended):
218
+ * const count = useSignal(0);
219
+ * count.set(10) or count.update(n => n + 1)
220
+ * ```
221
+ */
222
+ export function useState(initialState) {
223
+ return useReducer((state, action) => typeof action === "function" ? action(state) : action, initialState, typeof initialState === "function" ? initialState : undefined);
224
+ }
225
+ /**
226
+ * useReducer - State with reducer pattern.
227
+ */
228
+ export function useReducer(reducer, initialArg, init) {
229
+ const hook = mountOrUpdateHook(HookTag.Reducer);
230
+ const ctx = getCurrentContext();
231
+ const fiber = ctx.fiber;
232
+ // Capture scheduler at creation time to ensure concurrent compilations don't interfere
233
+ const scheduler = ctx.scheduleWork;
234
+ if (hook.queue === null) {
235
+ // Mount: initialize
236
+ // During hydration, memoizedState was already set from snapshot in mountWorkInProgressHook
237
+ // Only initialize if we don't have a hydrated value
238
+ const hasHydratedValue = ctx.isHydrating && hook.memoizedState !== undefined;
239
+ const initialState = hasHydratedValue
240
+ ? hook.memoizedState
241
+ : init
242
+ ? init(initialArg)
243
+ : initialArg;
244
+ hook.memoizedState = initialState;
245
+ hook.baseState = initialState;
246
+ const queue = {
247
+ pending: [], // Array instead of circular linked list - safer for concurrent dispatch
248
+ dispatch: null,
249
+ lastRenderedState: initialState,
250
+ };
251
+ hook.queue = queue;
252
+ const dispatch = (action) => {
253
+ dispatchAction(fiber, hook, queue, reducer, action, scheduler);
254
+ };
255
+ queue.dispatch = dispatch;
256
+ }
257
+ else {
258
+ // Update: process pending updates
259
+ const queue = hook.queue;
260
+ let newState = hook.baseState;
261
+ // Process all pending updates from the array
262
+ if (queue.pending.length > 0) {
263
+ for (const update of queue.pending) {
264
+ newState = reducer(newState, update.action);
265
+ }
266
+ // Clear the queue after processing
267
+ queue.pending = [];
268
+ }
269
+ hook.memoizedState = newState;
270
+ queue.lastRenderedState = newState;
271
+ }
272
+ return [hook.memoizedState, hook.queue.dispatch];
273
+ }
274
+ function dispatchAction(fiber, hook, queue, reducer, action, scheduler) {
275
+ const update = { action };
276
+ // Array.push is atomic in JavaScript's single-threaded model,
277
+ // avoiding race conditions that could occur with circular linked list manipulation
278
+ // when multiple async operations dispatch concurrently.
279
+ queue.pending.push(update);
280
+ // Eagerly compute for bailout
281
+ const current = hook.memoizedState;
282
+ const newState = reducer(current, action);
283
+ if (Object.is(current, newState)) {
284
+ return; // Bailout
285
+ }
286
+ // Use the captured scheduler, not the global one
287
+ if (scheduler) {
288
+ scheduler(fiber);
289
+ }
290
+ }
291
+ /**
292
+ * useSignal - Signal-based state in function components.
293
+ *
294
+ * Provides full signal API (not just [value, setter]).
295
+ * Automatically triggers recompiles when the signal is updated (like useState).
296
+ *
297
+ * @example
298
+ * ```tsx
299
+ * function Counter() {
300
+ * const count = useSignal(0);
301
+ * return <Text>Count: {count()}</Text>;
302
+ * }
303
+ * ```
304
+ */
305
+ export function useSignal(initialValue) {
306
+ const hook = mountOrUpdateHook(HookTag.Signal);
307
+ const ctx = getCurrentContext();
308
+ const fiber = ctx.fiber;
309
+ // Capture scheduler at creation time to ensure concurrent compilations don't interfere
310
+ const scheduler = ctx.scheduleWork;
311
+ if (hook.memoizedState === undefined) {
312
+ const baseSignal = createSignal(initialValue);
313
+ // Wrap set and update to trigger recompiles (like useState)
314
+ // This makes useSignal behave consistently with useState for triggering renders
315
+ const originalSet = baseSignal.set;
316
+ const originalUpdate = baseSignal.update;
317
+ const wrappedSet = (value) => {
318
+ originalSet(value);
319
+ // Trigger recompile if we have a fiber and we're not in a phase that should skip
320
+ // Use the captured scheduler, not the global one
321
+ if (fiber && !shouldSkipRecompile() && scheduler) {
322
+ scheduler(fiber);
323
+ }
324
+ };
325
+ const wrappedUpdate = (updater) => {
326
+ originalUpdate(updater);
327
+ // Trigger recompile if we have a fiber and we're not in a phase that should skip
328
+ // Use the captured scheduler, not the global one
329
+ if (fiber && !shouldSkipRecompile() && scheduler) {
330
+ scheduler(fiber);
331
+ }
332
+ };
333
+ // Create wrapped signal with original signal's functionality
334
+ const wrappedSignal = baseSignal;
335
+ wrappedSignal.set = wrappedSet;
336
+ wrappedSignal.update = wrappedUpdate;
337
+ hook.memoizedState = wrappedSignal;
338
+ }
339
+ return hook.memoizedState;
340
+ }
341
+ // ============================================================================
342
+ // COM STATE HOOKS
343
+ // ============================================================================
344
+ /**
345
+ * useComState - COM-bound shared state.
346
+ *
347
+ * Returns a signal bound to COM state. State is shared across all components
348
+ * and persisted. Changes automatically trigger recompilation.
349
+ *
350
+ * @example
351
+ * ```tsx
352
+ * function Timeline() {
353
+ * const messages = useComState('timeline', []);
354
+ * return <Timeline>{messages().map(...)}</Timeline>;
355
+ * }
356
+ * ```
357
+ */
358
+ export function useComState(key, initialValue) {
359
+ const hook = mountOrUpdateHook(HookTag.ComState);
360
+ const ctx = getCurrentContext();
361
+ if (hook.memoizedState === undefined) {
362
+ const signal = createCOMStateSignal(ctx.com, key, initialValue);
363
+ hook.memoizedState = signal;
364
+ // Cleanup on unmount
365
+ hook.effect = {
366
+ phase: EffectPhase.Unmount,
367
+ create: () => undefined,
368
+ destroy: () => signal.dispose(),
369
+ deps: null,
370
+ pending: false,
371
+ next: null,
372
+ };
373
+ }
374
+ // Safe to cast: initialValue is required, so T is never undefined
375
+ return hook.memoizedState;
376
+ }
377
+ /**
378
+ * useWatch - Read-only COM state observation.
379
+ * Returns a ReadonlySignal for reactive access to the watched state.
380
+ *
381
+ * @example
382
+ * ```tsx
383
+ * function StatusDisplay() {
384
+ * const status = useWatch('agentStatus', 'idle');
385
+ * return <Text>Status: {status()}</Text>;
386
+ * }
387
+ * ```
388
+ */
389
+ export function useWatch(key, defaultValue) {
390
+ const hook = mountOrUpdateHook(HookTag.WatchState);
391
+ const ctx = getCurrentContext();
392
+ if (hook.memoizedState === undefined) {
393
+ const signal = createReadonlyCOMStateSignal(ctx.com, key, defaultValue);
394
+ hook.memoizedState = signal;
395
+ hook.effect = {
396
+ phase: EffectPhase.Unmount,
397
+ create: () => undefined,
398
+ destroy: () => signal.dispose(),
399
+ deps: null,
400
+ pending: false,
401
+ next: null,
402
+ };
403
+ }
404
+ return hook.memoizedState;
405
+ }
406
+ /**
407
+ * useInput - Reactive prop access with default value.
408
+ */
409
+ export function useInput(propKey, defaultValue) {
410
+ const ctx = getCurrentContext();
411
+ const value = ctx.fiber.props[propKey];
412
+ return (value !== undefined ? value : defaultValue);
413
+ }
414
+ // ============================================================================
415
+ // EFFECT HOOKS
416
+ // ============================================================================
417
+ /**
418
+ * useEffect - Side effect after commit.
419
+ *
420
+ * Unlike React, callback CAN be async.
421
+ * Signals/computed values in deps array are automatically unwrapped.
422
+ *
423
+ * During hydration:
424
+ * - Mount effects (deps = []) are skipped (state is restored, not fresh)
425
+ * - Effects with deps still run (deps might have changed since snapshot)
426
+ *
427
+ * @example
428
+ * ```tsx
429
+ * function Logger() {
430
+ * const message = useComState('message', '');
431
+ *
432
+ * useEffect(async () => {
433
+ * await logToServer(message()); // Read signal value
434
+ * return () => console.log('cleanup');
435
+ * }, [message]); // Signal auto-tracked by value
436
+ * }
437
+ * ```
438
+ */
439
+ export function useEffect(create, deps) {
440
+ const hook = mountOrUpdateHook(HookTag.Effect);
441
+ const ctx = getCurrentContext();
442
+ // Unwrap signals in deps for comparison
443
+ const unwrappedDeps = unwrapDeps(deps);
444
+ // Check if this is a mount effect during hydration
445
+ // Mount effects have empty deps array: useEffect(fn, [])
446
+ const isMountEffect = Array.isArray(unwrappedDeps) && unwrappedDeps.length === 0;
447
+ const isHydratingMount = ctx.isHydrating && isMountEffect && hook.effect === null;
448
+ // Skip mount effects during hydration - state is restored, not fresh
449
+ if (isHydratingMount) {
450
+ // Still create the effect structure but mark as not pending
451
+ hook.effect = {
452
+ phase: EffectPhase.Commit,
453
+ create,
454
+ destroy: null,
455
+ deps: unwrappedDeps ?? null,
456
+ pending: false, // Don't run during hydration
457
+ next: null,
458
+ };
459
+ return;
460
+ }
461
+ const hasDepsChanged = hook.effect === null ||
462
+ unwrappedDeps === undefined ||
463
+ unwrappedDeps === null ||
464
+ !areHookInputsEqual(unwrappedDeps, hook.effect.deps);
465
+ if (hasDepsChanged) {
466
+ hook.effect = {
467
+ phase: EffectPhase.Commit,
468
+ create,
469
+ destroy: hook.effect?.destroy ?? null,
470
+ deps: unwrappedDeps ?? null,
471
+ pending: true,
472
+ next: null,
473
+ };
474
+ }
475
+ }
476
+ /**
477
+ * useInit - Component initialization that runs once on mount.
478
+ * Can be async and should be awaited if it returns a Promise.
479
+ * Runs DURING render, blocking until complete.
480
+ *
481
+ * Use for: loading initial data, setting up state before first render
482
+ *
483
+ * @example
484
+ * ```tsx
485
+ * function MyComponent() {
486
+ * const data = useComState('data', []);
487
+ *
488
+ * await useInit(async (com, state) => {
489
+ * const initialData = await loadData();
490
+ * data.set(initialData);
491
+ * });
492
+ *
493
+ * return <Section>{data().map(...)}</Section>;
494
+ * }
495
+ * ```
496
+ */
497
+ export async function useInit(callback) {
498
+ const ctx = getCurrentContext();
499
+ const hook = mountOrUpdateHook(HookTag.Memo);
500
+ if (hook.memoizedState === undefined) {
501
+ const result = callback(ctx.com, ctx.tickState);
502
+ const promise = result instanceof Promise ? result : Promise.resolve();
503
+ hook.memoizedState = promise;
504
+ await promise;
505
+ return;
506
+ }
507
+ // Already initialized - return cached promise
508
+ (await hook.memoizedState);
509
+ }
510
+ /**
511
+ * useOnMount - Run once when component mounts as a side effect.
512
+ * Runs AFTER render (as an effect), does not block rendering.
513
+ * Use for non-critical side effects like logging, analytics.
514
+ *
515
+ * For blocking initialization, use `useInit` instead.
516
+ *
517
+ * @example
518
+ * ```tsx
519
+ * function MyComponent() {
520
+ * useOnMount((com) => {
521
+ * log.info('Component mounted');
522
+ * });
523
+ * return <Text>Hello</Text>;
524
+ * }
525
+ * ```
526
+ */
527
+ export function useOnMount(callback) {
528
+ const ctx = getCurrentContext();
529
+ useEffect(() => {
530
+ callback(ctx.com);
531
+ }, []);
532
+ }
533
+ /**
534
+ * useOnUnmount - Run once when component unmounts.
535
+ */
536
+ export function useOnUnmount(callback) {
537
+ const ctx = getCurrentContext();
538
+ useEffect(() => {
539
+ return () => callback(ctx.com);
540
+ }, []);
541
+ }
542
+ /**
543
+ * useTickStart - Run at start of each tick, before render.
544
+ *
545
+ * @deprecated Use `useOnTickStart` instead for consistent naming convention.
546
+ */
547
+ export function useTickStart(callback) {
548
+ const hook = mountOrUpdateHook(HookTag.TickStart);
549
+ const ctx = getCurrentContext();
550
+ // Always pending - runs every tick
551
+ hook.effect = {
552
+ phase: EffectPhase.TickStart,
553
+ create: () => callback(ctx.com, ctx.tickState),
554
+ destroy: null,
555
+ deps: null,
556
+ pending: true,
557
+ next: null,
558
+ };
559
+ hook.memoizedState = callback;
560
+ }
561
+ /**
562
+ * useTickEnd - Run at end of each tick, after model execution.
563
+ *
564
+ * @deprecated Use `useOnTickEnd` instead for consistent naming convention.
565
+ */
566
+ export function useTickEnd(callback) {
567
+ const hook = mountOrUpdateHook(HookTag.TickEnd);
568
+ const ctx = getCurrentContext();
569
+ hook.effect = {
570
+ phase: EffectPhase.TickEnd,
571
+ create: () => callback(ctx.com, ctx.tickState),
572
+ destroy: null,
573
+ deps: null,
574
+ pending: true,
575
+ next: null,
576
+ };
577
+ hook.memoizedState = callback;
578
+ }
579
+ /**
580
+ * useAfterCompile - Run after compile, can request recompile.
581
+ *
582
+ * @deprecated Use `useOnAfterCompile` instead for consistent naming convention.
583
+ */
584
+ export function useAfterCompile(callback) {
585
+ const hook = mountOrUpdateHook(HookTag.AfterCompile);
586
+ const _ctx = getCurrentContext();
587
+ // Store callback and create effect
588
+ hook.memoizedState = callback;
589
+ hook.effect = {
590
+ phase: EffectPhase.AfterCompile,
591
+ create: () => {
592
+ // Will be called by compiler with compiled structure
593
+ return undefined;
594
+ },
595
+ destroy: null,
596
+ deps: null,
597
+ pending: true,
598
+ next: null,
599
+ };
600
+ }
601
+ /**
602
+ * useOnMessage - Handle execution messages.
603
+ *
604
+ * Called immediately when messages are sent to the running execution via:
605
+ * - RuntimeSession.sendMessage() - Direct programmatic injection
606
+ * - ExecutionHandle.send() - Via handle reference
607
+ * - Channel events with type='message' - From client
608
+ *
609
+ * Messages are processed immediately when they arrive, not at tick boundaries.
610
+ * Use com.abort() to interrupt execution if needed, or update state for the next tick.
611
+ * Messages are also available in TickState.queuedMessages during render.
612
+ *
613
+ * @example
614
+ * ```tsx
615
+ * function InteractiveAgent() {
616
+ * const feedback = useComState('userFeedback', []);
617
+ *
618
+ * useOnMessage((com, message, state) => {
619
+ * if (message.type === 'stop') {
620
+ * com.abort('User requested stop');
621
+ * } else if (message.type === 'feedback') {
622
+ * feedback.update(f => [...f, message.content]);
623
+ * }
624
+ * });
625
+ *
626
+ * return <Section>{feedback().map(f => <Paragraph>{f}</Paragraph>)}</Section>;
627
+ * }
628
+ * ```
629
+ */
630
+ export function useOnMessage(callback) {
631
+ const hook = mountOrUpdateHook(HookTag.OnMessage);
632
+ // Store the latest callback in memoizedState
633
+ // This will be retrieved and called by notifyOnMessage in FiberCompiler
634
+ hook.memoizedState = callback;
635
+ // Mark with OnMessage tag for identification during traversal
636
+ hook.effect = {
637
+ phase: EffectPhase.OnMessage,
638
+ create: () => undefined, // Will be called dynamically with message
639
+ destroy: null,
640
+ deps: null,
641
+ pending: false, // Not pending by default - only runs when message arrives
642
+ next: null,
643
+ };
644
+ }
645
+ // ============================================================================
646
+ // LIFECYCLE HOOKS (useOn* naming convention)
647
+ // ============================================================================
648
+ /**
649
+ * useOnTickStart - Run at start of each tick, before render.
650
+ *
651
+ * This is the canonical hook for tick-start lifecycle.
652
+ * Alias: useTickStart (deprecated, prefer useOnTickStart)
653
+ *
654
+ * @example
655
+ * ```tsx
656
+ * function MyAgent() {
657
+ * useOnTickStart((com, state) => {
658
+ * console.log(`Starting tick ${state.tick}`);
659
+ * });
660
+ * return <System>You are helpful.</System>;
661
+ * }
662
+ * ```
663
+ */
664
+ export function useOnTickStart(callback) {
665
+ useTickStart(callback);
666
+ }
667
+ /**
668
+ * useOnAfterRender - Run after render/reconciliation, before compile.
669
+ *
670
+ * Use this to inspect or modify state after all components have rendered
671
+ * but before the context is compiled and sent to the model.
672
+ *
673
+ * @example
674
+ * ```tsx
675
+ * function MyAgent() {
676
+ * useOnAfterRender((com, state) => {
677
+ * console.log('Components rendered, about to compile');
678
+ * });
679
+ * return <System>You are helpful.</System>;
680
+ * }
681
+ * ```
682
+ */
683
+ export function useOnAfterRender(callback) {
684
+ const hook = mountOrUpdateHook(HookTag.AfterRender);
685
+ const ctx = getCurrentContext();
686
+ hook.effect = {
687
+ phase: EffectPhase.AfterRender,
688
+ create: () => callback(ctx.com, ctx.tickState),
689
+ destroy: null,
690
+ deps: null,
691
+ pending: true,
692
+ next: null,
693
+ };
694
+ hook.memoizedState = callback;
695
+ }
696
+ /**
697
+ * useOnAfterCompile - Run after compile, before model call.
698
+ *
699
+ * Use this to transform the compiled structure before it's sent to the model.
700
+ * Can request recompile if needed.
701
+ *
702
+ * This is the canonical hook for after-compile lifecycle.
703
+ * Alias: useAfterCompile (deprecated, prefer useOnAfterCompile)
704
+ *
705
+ * @example
706
+ * ```tsx
707
+ * function MyAgent() {
708
+ * useOnAfterCompile((com, compiled, state) => {
709
+ * // Inspect or modify compiled structure
710
+ * if (compiled.tokenCount > 10000) {
711
+ * // Request summarization
712
+ * }
713
+ * });
714
+ * return <System>You are helpful.</System>;
715
+ * }
716
+ * ```
717
+ */
718
+ export function useOnAfterCompile(callback) {
719
+ useAfterCompile(callback);
720
+ }
721
+ /**
722
+ * useOnTickEnd - Run at end of each tick, after model execution.
723
+ *
724
+ * Use this to process model response, decide on continuation, or clean up.
725
+ *
726
+ * This is the canonical hook for tick-end lifecycle.
727
+ * Alias: useTickEnd (deprecated, prefer useOnTickEnd)
728
+ *
729
+ * @example
730
+ * ```tsx
731
+ * function MyAgent() {
732
+ * useOnTickEnd((com, state) => {
733
+ * console.log(`Tick ${state.tick} complete`);
734
+ * if (state.response?.stopReason === 'stop') {
735
+ * com.complete();
736
+ * }
737
+ * });
738
+ * return <System>You are helpful.</System>;
739
+ * }
740
+ * ```
741
+ */
742
+ export function useOnTickEnd(callback) {
743
+ useTickEnd(callback);
744
+ }
745
+ /**
746
+ * useOnComplete - Run when session completes (all ticks done).
747
+ *
748
+ * This hook runs once when the session finishes execution, whether through:
749
+ * - Natural completion (shouldContinue returns false)
750
+ * - Explicit com.complete() call
751
+ * - Error or abort
752
+ *
753
+ * Use this for cleanup, final logging, or teardown logic.
754
+ *
755
+ * @example
756
+ * ```tsx
757
+ * function MyAgent() {
758
+ * useOnComplete((com, state) => {
759
+ * console.log(`Session complete after ${state.tick} ticks`);
760
+ * // Cleanup resources
761
+ * });
762
+ * return <System>You are helpful.</System>;
763
+ * }
764
+ * ```
765
+ */
766
+ export function useOnComplete(callback) {
767
+ const hook = mountOrUpdateHook(HookTag.Complete);
768
+ const ctx = getCurrentContext();
769
+ hook.effect = {
770
+ phase: EffectPhase.Complete,
771
+ create: () => callback(ctx.com, ctx.tickState),
772
+ destroy: null,
773
+ deps: null,
774
+ pending: true,
775
+ next: null,
776
+ };
777
+ hook.memoizedState = callback;
778
+ }
779
+ // ============================================================================
780
+ // ASYNC HOOKS
781
+ // ============================================================================
782
+ /**
783
+ * useAsync - Async data fetching.
784
+ *
785
+ * Unlike React (which needs Suspense), we just track loading state.
786
+ * The tick can wait for async work to complete.
787
+ *
788
+ * @example
789
+ * ```tsx
790
+ * function UserProfile({ userId }) {
791
+ * const { data: user, loading, error } = useAsync(
792
+ * () => fetchUser(userId),
793
+ * [userId]
794
+ * );
795
+ *
796
+ * if (loading) return null;
797
+ * if (error) return <Text>Error: {error.message}</Text>;
798
+ *
799
+ * return <Text>User: {user.name}</Text>;
800
+ * }
801
+ * ```
802
+ */
803
+ export function useAsync(asyncFn, deps) {
804
+ const [state, setState] = useState({
805
+ data: undefined,
806
+ loading: true,
807
+ error: undefined,
808
+ });
809
+ // Track if deps changed
810
+ const prevDeps = useRef(null);
811
+ const depsChanged = prevDeps.current === null || !areHookInputsEqual(deps, prevDeps.current);
812
+ prevDeps.current = deps;
813
+ // Only trigger on deps change
814
+ if (depsChanged && state.loading === false) {
815
+ setState({ data: undefined, loading: true, error: undefined });
816
+ }
817
+ useEffect(() => {
818
+ let cancelled = false;
819
+ asyncFn()
820
+ .then((data) => {
821
+ if (!cancelled) {
822
+ setState({ data, loading: false, error: undefined });
823
+ }
824
+ })
825
+ .catch((error) => {
826
+ if (!cancelled) {
827
+ setState({ data: undefined, loading: false, error });
828
+ }
829
+ });
830
+ return () => {
831
+ cancelled = true;
832
+ };
833
+ }, deps);
834
+ return state;
835
+ }
836
+ // ============================================================================
837
+ // MEMOIZATION HOOKS
838
+ // ============================================================================
839
+ /**
840
+ * useMemo - Memoize expensive computation.
841
+ */
842
+ export function useMemo(factory, deps) {
843
+ const hook = mountOrUpdateHook(HookTag.Memo);
844
+ const memoState = hook.memoizedState;
845
+ const prevDeps = memoState?.[1];
846
+ if (prevDeps !== undefined && areHookInputsEqual(deps, prevDeps)) {
847
+ return memoState[0];
848
+ }
849
+ const value = factory();
850
+ hook.memoizedState = [value, deps];
851
+ return value;
852
+ }
853
+ /**
854
+ * useComputed - Create a reactive computed signal that persists across renders.
855
+ *
856
+ * Unlike useMemo which returns a plain value, useComputed returns a ComputedSignal
857
+ * that automatically tracks dependencies and updates when they change.
858
+ * The computed signal is disposed and recreated only when deps change.
859
+ *
860
+ * @example
861
+ * ```typescript
862
+ * const timeline = useComState('timeline', []);
863
+ * const recentMessages = useComputed(() => timeline().slice(-10), []);
864
+ *
865
+ * // Read the computed value
866
+ * const messages = recentMessages(); // or recentMessages.value
867
+ * ```
868
+ */
869
+ export function useComputed(computation, deps = []) {
870
+ const hook = mountOrUpdateHook(HookTag.Memo);
871
+ const memoState = hook.memoizedState;
872
+ const prevDeps = memoState?.[1];
873
+ // If deps haven't changed, return existing computed
874
+ if (prevDeps !== undefined && areHookInputsEqual(deps, prevDeps)) {
875
+ return memoState[0];
876
+ }
877
+ // Deps changed or first render - dispose old computed if it exists
878
+ if (memoState?.[0]) {
879
+ memoState[0].dispose();
880
+ }
881
+ // Create new computed signal
882
+ const computedSignal = computed(computation);
883
+ hook.memoizedState = [computedSignal, deps];
884
+ return computedSignal;
885
+ }
886
+ /**
887
+ * useCallback - Memoize callback function.
888
+ */
889
+ export function useCallback(callback, deps) {
890
+ return useMemo(() => callback, deps);
891
+ }
892
+ // ============================================================================
893
+ // REF HOOKS
894
+ // ============================================================================
895
+ /**
896
+ * useRef - Mutable ref that persists across renders.
897
+ */
898
+ export function useRef(initialValue) {
899
+ const hook = mountOrUpdateHook(HookTag.Ref);
900
+ const ctx = getCurrentContext();
901
+ if (hook.memoizedState === undefined) {
902
+ hook.memoizedState = { current: initialValue };
903
+ }
904
+ else if (ctx.isHydrating &&
905
+ hook.memoizedState !== null &&
906
+ typeof hook.memoizedState !== "object") {
907
+ // During hydration, memoizedState is the raw value (not wrapped in { current })
908
+ // because serialization extracts ref.current for JSON serialization
909
+ hook.memoizedState = { current: hook.memoizedState };
910
+ }
911
+ return hook.memoizedState;
912
+ }
913
+ /**
914
+ * useCOMRef - Get component ref from COM.
915
+ */
916
+ export function useCOMRef(refName) {
917
+ const ctx = getCurrentContext();
918
+ return ctx.com.getRef(refName);
919
+ }
920
+ // ============================================================================
921
+ // UTILITY HOOKS
922
+ // ============================================================================
923
+ /**
924
+ * usePrevious - Track previous value.
925
+ */
926
+ export function usePrevious(value) {
927
+ const ref = useRef(undefined);
928
+ const previous = ref.current;
929
+ // Update ref during render (not in effect) so it's ready for next render
930
+ ref.current = value;
931
+ return previous;
932
+ }
933
+ /**
934
+ * useToggle - Boolean toggle state.
935
+ */
936
+ export function useToggle(initial = false) {
937
+ const sig = useSignal(initial);
938
+ const toggle = useCallback(() => sig.set((v) => !v), []);
939
+ return [sig(), toggle];
940
+ }
941
+ /**
942
+ * useCounter - Numeric counter.
943
+ */
944
+ export function useCounter(initial = 0) {
945
+ const [count, setCount] = useState(initial);
946
+ return {
947
+ count,
948
+ increment: useCallback(() => setCount((c) => c + 1), []),
949
+ decrement: useCallback(() => setCount((c) => c - 1), []),
950
+ set: setCount,
951
+ reset: useCallback(() => setCount(initial), [initial]),
952
+ };
953
+ }
954
+ /**
955
+ * useAbortSignal - Get abort signal for current execution.
956
+ */
957
+ export function useAbortSignal() {
958
+ const ctx = getCurrentContext();
959
+ return ctx.abortSignal;
960
+ }
961
+ /**
962
+ * useDebugValue - Display value in devtools (no-op in production).
963
+ */
964
+ export function useDebugValue(value, formatter) {
965
+ if (process.env["NODE_ENV"] === "development") {
966
+ const ctx = getCurrentContext();
967
+ ctx.fiber.debugName = String(formatter ? formatter(value) : value);
968
+ }
969
+ }
970
+ /**
971
+ * useTick - Control tick execution from within a component.
972
+ *
973
+ * This hook provides components with the ability to:
974
+ * - Request a new tick (e.g., when enough messages have accumulated)
975
+ * - Cancel a pending tick request
976
+ * - Check the current tick status
977
+ * - Get the total tick count
978
+ *
979
+ * @example
980
+ * ```tsx
981
+ * function BatchProcessor() {
982
+ * const { requestTick, tickStatus, tickCount } = useTick();
983
+ * const queue = useComState('queue', []);
984
+ *
985
+ * useEffect(() => {
986
+ * // Request tick when queue has 10 items and we're idle
987
+ * if (queue().length >= 10 && tickStatus === 'idle') {
988
+ * requestTick();
989
+ * }
990
+ * }, [queue().length, tickStatus]);
991
+ *
992
+ * return <Section>Tick {tickCount}: {queue().length} items</Section>;
993
+ * }
994
+ * ```
995
+ */
996
+ export function useTick() {
997
+ const ctx = getCurrentContext();
998
+ const tickControl = ctx.tickControl;
999
+ const tickState = ctx.tickState;
1000
+ // Default values if tick control not available
1001
+ const defaultResult = {
1002
+ requestTick: () => {
1003
+ if (process.env["NODE_ENV"] === "development") {
1004
+ console.warn("[useTick] requestTick called but tickControl not available. " +
1005
+ "Tick control is only available when running in a Session context.");
1006
+ }
1007
+ },
1008
+ cancelTick: () => {
1009
+ if (process.env["NODE_ENV"] === "development") {
1010
+ console.warn("[useTick] cancelTick called but tickControl not available. " +
1011
+ "Tick control is only available when running in a Session context.");
1012
+ }
1013
+ },
1014
+ tickStatus: "idle",
1015
+ tickCount: tickState?.tick ?? 0,
1016
+ };
1017
+ if (!tickControl) {
1018
+ return defaultResult;
1019
+ }
1020
+ return {
1021
+ requestTick: tickControl.requestTick,
1022
+ cancelTick: tickControl.cancelTick,
1023
+ tickStatus: tickControl.status,
1024
+ tickCount: tickControl.tickCount,
1025
+ };
1026
+ }
1027
+ /**
1028
+ * useChannel - Access a named channel for pub/sub communication.
1029
+ *
1030
+ * Channels enable real-time bidirectional communication between components
1031
+ * and external code (UI, other services, etc.).
1032
+ *
1033
+ * Use cases:
1034
+ * - User input during model execution (e.g., stop button, feedback)
1035
+ * - Progress updates to UI
1036
+ * - Tool confirmation dialogs
1037
+ * - Live data streaming to/from external systems
1038
+ *
1039
+ * @param name - Channel name (e.g., 'progress', 'user-input', 'tool:confirm')
1040
+ * @returns Channel access object with subscribe, publish, and waitForResponse
1041
+ *
1042
+ * @example Basic subscription
1043
+ * ```tsx
1044
+ * function ProgressDisplay() {
1045
+ * const [progress, setProgress] = useState(0);
1046
+ * const { subscribe, available } = useChannel('progress');
1047
+ *
1048
+ * useEffect(() => {
1049
+ * if (!available) return;
1050
+ * return subscribe((event) => {
1051
+ * if (event.type === 'update') {
1052
+ * setProgress(event.payload.percent);
1053
+ * }
1054
+ * });
1055
+ * }, [available]);
1056
+ *
1057
+ * return <Section>Progress: {progress}%</Section>;
1058
+ * }
1059
+ * ```
1060
+ *
1061
+ * @example Request/Response pattern
1062
+ * ```tsx
1063
+ * function ConfirmationHandler() {
1064
+ * const { publish, waitForResponse, available } = useChannel('confirmations');
1065
+ *
1066
+ * const confirmAction = async (action: string) => {
1067
+ * if (!available) throw new Error('Channels not available');
1068
+ *
1069
+ * const requestId = crypto.randomUUID();
1070
+ * publish({ type: 'request', id: requestId, payload: { action } });
1071
+ * const response = await waitForResponse(requestId, 30000);
1072
+ * return response.payload.confirmed;
1073
+ * };
1074
+ *
1075
+ * // ...
1076
+ * }
1077
+ * ```
1078
+ *
1079
+ * @example Publishing events
1080
+ * ```tsx
1081
+ * function StatusReporter() {
1082
+ * const { publish } = useChannel('status');
1083
+ *
1084
+ * useTickEnd(() => {
1085
+ * publish({ type: 'tick-complete', payload: { timestamp: Date.now() } });
1086
+ * });
1087
+ *
1088
+ * return null;
1089
+ * }
1090
+ * ```
1091
+ */
1092
+ export function useChannel(name) {
1093
+ const ctx = getCurrentContext();
1094
+ // Get the channel from the context (provided by Session)
1095
+ const channel = ctx.getChannel?.(name);
1096
+ // Default no-op implementations for when channels aren't available
1097
+ const unavailableResult = {
1098
+ channel: undefined,
1099
+ subscribe: () => {
1100
+ if (process.env["NODE_ENV"] === "development") {
1101
+ console.warn(`[useChannel] subscribe called on '${name}' but channel service not available. ` +
1102
+ "Channels require ChannelService configuration.");
1103
+ }
1104
+ return () => { }; // No-op unsubscribe
1105
+ },
1106
+ publish: () => {
1107
+ if (process.env["NODE_ENV"] === "development") {
1108
+ console.warn(`[useChannel] publish called on '${name}' but channel service not available. ` +
1109
+ "Channels require ChannelService configuration.");
1110
+ }
1111
+ },
1112
+ waitForResponse: () => {
1113
+ return Promise.reject(new Error(`Channel '${name}' not available. Channels require ChannelService configuration.`));
1114
+ },
1115
+ available: false,
1116
+ };
1117
+ if (!channel) {
1118
+ return unavailableResult;
1119
+ }
1120
+ return {
1121
+ channel,
1122
+ subscribe: (handler) => channel.subscribe(handler),
1123
+ publish: (event) => channel.publish({ ...event, channel: name }),
1124
+ waitForResponse: (requestId, timeoutMs) => channel.waitForResponse(requestId, timeoutMs),
1125
+ available: true,
1126
+ };
1127
+ }
1128
+ /**
1129
+ * useChannelSubscription - Subscribe to channel events with automatic cleanup.
1130
+ *
1131
+ * This is a convenience hook that combines useChannel with useEffect for
1132
+ * the common pattern of subscribing to a channel and cleaning up on unmount.
1133
+ *
1134
+ * @param name - Channel name
1135
+ * @param handler - Event handler function
1136
+ * @param deps - Dependencies array (handler is only updated when deps change)
1137
+ *
1138
+ * @example
1139
+ * ```tsx
1140
+ * function NotificationListener() {
1141
+ * const [notifications, setNotifications] = useState<string[]>([]);
1142
+ *
1143
+ * useChannelSubscription('notifications', (event) => {
1144
+ * if (event.type === 'new') {
1145
+ * setNotifications(n => [...n, event.payload.message]);
1146
+ * }
1147
+ * }, []);
1148
+ *
1149
+ * return <Section>{notifications.map(n => <Text>{n}</Text>)}</Section>;
1150
+ * }
1151
+ * ```
1152
+ */
1153
+ export function useChannelSubscription(name, handler, deps = []) {
1154
+ const { subscribe, available } = useChannel(name);
1155
+ // Use a ref to store the latest handler to avoid stale closures
1156
+ const handlerRef = useRef(handler);
1157
+ handlerRef.current = handler;
1158
+ useEffect(() => {
1159
+ if (!available)
1160
+ return;
1161
+ // Subscribe with a wrapper that always uses the latest handler
1162
+ return subscribe((event) => handlerRef.current(event));
1163
+ }, [available, ...deps]);
1164
+ }
1165
+ /**
1166
+ * Get the full conversation history across all ticks.
1167
+ *
1168
+ * Combines `state.previous.timeline` (history) with `state.current.timeline`
1169
+ * (current tick) into a single array.
1170
+ *
1171
+ * This is a utility hook that extracts data from TickState - it doesn't use the
1172
+ * fiber system and can be called anywhere you have access to TickState.
1173
+ *
1174
+ * @param state - The TickState from component context
1175
+ * @param options - Optional filtering and limiting
1176
+ * @returns Array of timeline entries
1177
+ *
1178
+ * @example Basic usage
1179
+ * ```tsx
1180
+ * const ChatAgent = ({ message }: Props) => {
1181
+ * const history = useConversationHistory();
1182
+ *
1183
+ * return (
1184
+ * <>
1185
+ * <Model model={claude} />
1186
+ * <System>You are helpful.</System>
1187
+ * {history.map((entry, i) => (
1188
+ * <Message key={i} {...entry.message} />
1189
+ * ))}
1190
+ * <User>{message}</User>
1191
+ * </>
1192
+ * );
1193
+ * };
1194
+ * ```
1195
+ *
1196
+ * @example With options
1197
+ * ```tsx
1198
+ * const history = useConversationHistory({
1199
+ * roles: ['user', 'assistant'], // Exclude tool messages
1200
+ * limit: 10, // Last 10 messages
1201
+ * });
1202
+ * ```
1203
+ */
1204
+ export function useConversationHistory(options) {
1205
+ const state = useTickState();
1206
+ const com = useCom();
1207
+ // This hook returns PURE DATA for components to render.
1208
+ // Components render this data as <Message> projections.
1209
+ // The compiled output IS what the model sees - JSX is the single source of truth.
1210
+ //
1211
+ // Sources:
1212
+ // - previous: History from previous ticks (the main conversation history)
1213
+ // - current: Model output from last tick (may overlap with previous)
1214
+ // - injected: Entries added via com.injectHistory() during this tick
1215
+ // - pending: Queued messages for THIS tick (new user input)
1216
+ //
1217
+ // Deduplication by message reference prevents double-counting.
1218
+ const seen = new Set();
1219
+ let entries = [];
1220
+ const addEntries = (source, sourceName) => {
1221
+ const count = source?.length ?? 0;
1222
+ log.debug({ source: sourceName, count }, "useConversationHistory adding entries from source");
1223
+ if (!source)
1224
+ return;
1225
+ for (const entry of source) {
1226
+ // Dedupe by message reference for entries with messages
1227
+ if (entry.message) {
1228
+ if (seen.has(entry.message))
1229
+ continue;
1230
+ seen.add(entry.message);
1231
+ }
1232
+ entries.push(entry);
1233
+ }
1234
+ };
1235
+ // Add all sources - this is DATA for components to render
1236
+ addEntries(state.previous?.timeline, "state.previous.timeline");
1237
+ addEntries(state.current?.timeline, "state.current.timeline");
1238
+ addEntries(com.getInjectedHistory(), "com.getInjectedHistory()");
1239
+ // Include pending messages (queued for this tick)
1240
+ const pending = state.queuedMessages || [];
1241
+ for (const msg of pending) {
1242
+ if (msg.type === "user" && msg.content && typeof msg.content === "object" && "role" in msg.content) {
1243
+ const message = msg.content;
1244
+ if (message && !seen.has(message)) {
1245
+ seen.add(message);
1246
+ entries.push({
1247
+ kind: "message",
1248
+ message,
1249
+ tags: ["pending", "user_input"],
1250
+ });
1251
+ log.debug({ role: message.role }, "useConversationHistory added pending message");
1252
+ }
1253
+ }
1254
+ }
1255
+ log.debug({ totalEntries: entries.length }, "useConversationHistory total entries");
1256
+ // Apply role filter if specified
1257
+ if (options?.roles) {
1258
+ const roleSet = new Set(options.roles);
1259
+ entries = entries.filter((entry) => entry.message?.role && roleSet.has(entry.message.role));
1260
+ }
1261
+ // Apply custom filter
1262
+ if (options?.filter) {
1263
+ entries = entries.filter(options.filter);
1264
+ }
1265
+ // Apply limit (from end)
1266
+ if (options?.limit && options.limit > 0) {
1267
+ entries = entries.slice(-options.limit);
1268
+ }
1269
+ return entries;
1270
+ }
1271
+ /**
1272
+ * Get just the messages from conversation history (convenience wrapper).
1273
+ *
1274
+ * @param options - Optional filtering and limiting
1275
+ * @returns Array of messages (excluding entries without messages)
1276
+ */
1277
+ export function useMessages(options) {
1278
+ return useConversationHistory(options)
1279
+ .filter((entry) => entry.message)
1280
+ .map((entry) => entry.message);
1281
+ }
1282
+ /**
1283
+ * Get message count from conversation history.
1284
+ *
1285
+ * @returns Number of messages in history
1286
+ */
1287
+ export function useMessageCount() {
1288
+ return useConversationHistory().filter((entry) => entry.message).length;
1289
+ }
1290
+ /**
1291
+ * Get messages queued for the next tick.
1292
+ *
1293
+ * Messages can be queued via:
1294
+ * - `session.queue.exec(msg)` - Queue a message for later processing
1295
+ * - `session.interrupt(msg)` - Interrupt and queue a message
1296
+ * - `RuntimeSession.sendMessage(msg)` - Direct programmatic injection
1297
+ *
1298
+ * Queued messages are available during render and can be used to show
1299
+ * pending messages in the UI or to process them in the current tick.
1300
+ *
1301
+ * @returns Array of queued execution messages
1302
+ *
1303
+ * @example Show pending messages
1304
+ * ```tsx
1305
+ * const ChatWithPending = () => {
1306
+ * const history = useConversationHistory();
1307
+ * const pending = useQueuedMessages();
1308
+ *
1309
+ * return (
1310
+ * <>
1311
+ * {history.map((entry, i) => (
1312
+ * <Message key={i} {...entry.message} />
1313
+ * ))}
1314
+ * {pending.length > 0 && (
1315
+ * <System>Processing {pending.length} pending message(s)...</System>
1316
+ * )}
1317
+ * </>
1318
+ * );
1319
+ * };
1320
+ * ```
1321
+ *
1322
+ * @example Process pending messages
1323
+ * ```tsx
1324
+ * const Agent = () => {
1325
+ * const pending = useQueuedMessages();
1326
+ *
1327
+ * // Access the first pending message if any
1328
+ * const firstPending = pending[0];
1329
+ * if (firstPending?.type === 'interrupt') {
1330
+ * return <System>Handling interrupt: {firstPending.content}</System>;
1331
+ * }
1332
+ *
1333
+ * return <AssistantMessage />;
1334
+ * };
1335
+ * ```
1336
+ */
1337
+ export function useQueuedMessages() {
1338
+ const state = useTickState();
1339
+ return state.queuedMessages ?? [];
1340
+ }
1341
+ // ============================================================================
1342
+ // History Injection Hooks
1343
+ // ============================================================================
1344
+ /**
1345
+ * Inject historical timeline entries into the conversation.
1346
+ *
1347
+ * Use this to load an existing conversation when the component mounts.
1348
+ * The entries are injected once (on first render) and then available via
1349
+ * `useConversationHistory()` and `<Timeline />`.
1350
+ *
1351
+ * This hook only injects on the first render. On subsequent renders (tick 2+),
1352
+ * the timeline naturally includes all entries via `TickState.previous.timeline`.
1353
+ *
1354
+ * @param entries - Timeline entries to inject, or a function that returns them
1355
+ * @param deps - Dependency array (like useEffect). If omitted, injects once on mount.
1356
+ *
1357
+ * @example Basic usage with static entries
1358
+ * ```tsx
1359
+ * const ChatAgent = ({ conversationHistory }: Props) => {
1360
+ * useInjectHistory(conversationHistory);
1361
+ * return <Timeline />;
1362
+ * };
1363
+ * ```
1364
+ *
1365
+ * @example Async loading in useInit
1366
+ * ```tsx
1367
+ * const ChatAgent = ({ conversationId }: Props) => {
1368
+ * const [loaded, setLoaded] = useState(false);
1369
+ *
1370
+ * await useInit(async () => {
1371
+ * const conversation = await loadConversation(conversationId);
1372
+ * injectHistory(conversation.entries); // Use standalone function
1373
+ * setLoaded(true);
1374
+ * });
1375
+ *
1376
+ * if (!loaded) return null;
1377
+ * return <Timeline />;
1378
+ * };
1379
+ * ```
1380
+ */
1381
+ export function useInjectHistory(entries, deps) {
1382
+ const com = useCom();
1383
+ const hasInjected = useRef(false);
1384
+ // Resolve entries (can be array or function)
1385
+ const resolvedEntries = typeof entries === "function" ? entries() : entries;
1386
+ // Only inject once (unless deps change)
1387
+ const shouldInject = deps
1388
+ ? !hasInjected.current // With deps, use ref to track
1389
+ : !hasInjected.current; // Without deps, also use ref
1390
+ if (shouldInject && resolvedEntries.length > 0) {
1391
+ com.injectHistory(resolvedEntries);
1392
+ hasInjected.current = true;
1393
+ }
1394
+ }
1395
+ /**
1396
+ * Standalone function to inject history (for use in useInit or async contexts).
1397
+ *
1398
+ * Unlike the hook, this can be called anywhere you have access to COM.
1399
+ *
1400
+ * @param com - The COM instance
1401
+ * @param entries - Timeline entries to inject
1402
+ *
1403
+ * @example
1404
+ * ```tsx
1405
+ * const ChatAgent = ({ conversationId }: Props) => {
1406
+ * const com = useCom();
1407
+ *
1408
+ * await useInit(async () => {
1409
+ * const conversation = await loadConversation(conversationId);
1410
+ * injectHistory(com, conversation.entries);
1411
+ * });
1412
+ *
1413
+ * return <Timeline />;
1414
+ * };
1415
+ * ```
1416
+ */
1417
+ export function injectHistory(com, entries) {
1418
+ com.injectHistory(entries);
1419
+ }
1420
+ // ============================================================================
1421
+ // Helpers
1422
+ // ============================================================================
1423
+ function areHookInputsEqual(nextDeps, prevDeps) {
1424
+ if (prevDeps === null)
1425
+ return false;
1426
+ if (process.env["NODE_ENV"] === "development" && nextDeps.length !== prevDeps.length) {
1427
+ console.warn("Hook dependency array changed size between renders. " +
1428
+ "The array must remain constant in length.");
1429
+ }
1430
+ for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
1431
+ if (Object.is(nextDeps[i], prevDeps[i]))
1432
+ continue;
1433
+ return false;
1434
+ }
1435
+ return true;
1436
+ }
1437
+ //# sourceMappingURL=hooks.js.map