agent-nuvira 3.3.3 → 3.3.4

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 (349) hide show
  1. package/README.md +13 -5
  2. package/dist/agent-sdk/src/agent.d.ts +2 -0
  3. package/dist/agent-sdk/src/agent.d.ts.map +1 -1
  4. package/dist/agent-sdk/src/define.d.ts +64 -0
  5. package/dist/agent-sdk/src/define.d.ts.map +1 -0
  6. package/dist/agent-sdk/src/define.js +76 -0
  7. package/dist/agent-sdk/src/define.js.map +1 -0
  8. package/dist/agent-sdk/src/index.d.ts +9 -0
  9. package/dist/agent-sdk/src/index.d.ts.map +1 -1
  10. package/dist/agent-sdk/src/index.js +9 -0
  11. package/dist/agent-sdk/src/index.js.map +1 -1
  12. package/dist/agent-sdk/src/scaffold.d.ts +11 -0
  13. package/dist/agent-sdk/src/scaffold.d.ts.map +1 -1
  14. package/dist/agent-sdk/src/scaffold.js +16 -6
  15. package/dist/agent-sdk/src/scaffold.js.map +1 -1
  16. package/dist/agents/long-form-plan.d.ts.map +1 -1
  17. package/dist/agents/long-form-plan.js +2 -1
  18. package/dist/agents/long-form-plan.js.map +1 -1
  19. package/dist/agents/orchestrator.d.ts.map +1 -1
  20. package/dist/agents/orchestrator.js +5 -4
  21. package/dist/agents/orchestrator.js.map +1 -1
  22. package/dist/cli/agent.d.ts +2 -2
  23. package/dist/cli/agent.js +10 -10
  24. package/dist/cli/chat.d.ts +94 -0
  25. package/dist/cli/chat.d.ts.map +1 -1
  26. package/dist/cli/chat.js +354 -20
  27. package/dist/cli/chat.js.map +1 -1
  28. package/dist/cli/cli-program.d.ts.map +1 -1
  29. package/dist/cli/cli-program.js +5 -0
  30. package/dist/cli/cli-program.js.map +1 -1
  31. package/dist/cli/config.d.ts.map +1 -1
  32. package/dist/cli/config.js +9 -1
  33. package/dist/cli/config.js.map +1 -1
  34. package/dist/cli/doctor.d.ts.map +1 -1
  35. package/dist/cli/doctor.js +3 -2
  36. package/dist/cli/doctor.js.map +1 -1
  37. package/dist/cli/edit.js +2 -2
  38. package/dist/cli/eval.d.ts +17 -0
  39. package/dist/cli/eval.d.ts.map +1 -1
  40. package/dist/cli/eval.js +105 -2
  41. package/dist/cli/eval.js.map +1 -1
  42. package/dist/cli/execute.d.ts +16 -1
  43. package/dist/cli/execute.d.ts.map +1 -1
  44. package/dist/cli/execute.js +192 -22
  45. package/dist/cli/execute.js.map +1 -1
  46. package/dist/cli/loop-executor.d.ts +55 -0
  47. package/dist/cli/loop-executor.d.ts.map +1 -1
  48. package/dist/cli/loop-executor.js +212 -13
  49. package/dist/cli/loop-executor.js.map +1 -1
  50. package/dist/cli/model.d.ts.map +1 -1
  51. package/dist/cli/model.js +9 -8
  52. package/dist/cli/model.js.map +1 -1
  53. package/dist/cli/models.d.ts +1 -1
  54. package/dist/cli/models.js +4 -4
  55. package/dist/cli/parity.d.ts +85 -0
  56. package/dist/cli/parity.d.ts.map +1 -0
  57. package/dist/cli/parity.js +506 -0
  58. package/dist/cli/parity.js.map +1 -0
  59. package/dist/cli/plan.d.ts.map +1 -1
  60. package/dist/cli/plan.js +2 -1
  61. package/dist/cli/plan.js.map +1 -1
  62. package/dist/cli/retrieval.d.ts.map +1 -1
  63. package/dist/cli/retrieval.js +5 -4
  64. package/dist/cli/retrieval.js.map +1 -1
  65. package/dist/cli/sdk.js +4 -4
  66. package/dist/cli/sdk.js.map +1 -1
  67. package/dist/cli/trace.d.ts.map +1 -1
  68. package/dist/cli/trace.js +2 -1
  69. package/dist/cli/trace.js.map +1 -1
  70. package/dist/cli/workflow.js +2 -2
  71. package/dist/cli/workflow.js.map +1 -1
  72. package/dist/config/types.d.ts +44 -0
  73. package/dist/config/types.d.ts.map +1 -1
  74. package/dist/findings/verdicts.d.ts +241 -0
  75. package/dist/findings/verdicts.d.ts.map +1 -0
  76. package/dist/findings/verdicts.js +284 -0
  77. package/dist/findings/verdicts.js.map +1 -0
  78. package/dist/gateway/adapters.d.ts +65 -0
  79. package/dist/gateway/adapters.d.ts.map +1 -1
  80. package/dist/gateway/adapters.js +216 -10
  81. package/dist/gateway/adapters.js.map +1 -1
  82. package/dist/gateway/channel-directory.d.ts +31 -0
  83. package/dist/gateway/channel-directory.d.ts.map +1 -1
  84. package/dist/gateway/channel-directory.js +40 -0
  85. package/dist/gateway/channel-directory.js.map +1 -1
  86. package/dist/gateway/gateway-log.d.ts +1 -1
  87. package/dist/gateway/gateway-log.d.ts.map +1 -1
  88. package/dist/gateway/gateway-log.js.map +1 -1
  89. package/dist/gateway/hooks.d.ts +87 -19
  90. package/dist/gateway/hooks.d.ts.map +1 -1
  91. package/dist/gateway/hooks.js +62 -23
  92. package/dist/gateway/hooks.js.map +1 -1
  93. package/dist/gateway/inbound-media.d.ts +147 -0
  94. package/dist/gateway/inbound-media.d.ts.map +1 -0
  95. package/dist/gateway/inbound-media.js +317 -0
  96. package/dist/gateway/inbound-media.js.map +1 -0
  97. package/dist/gateway/inbox.d.ts +8 -1
  98. package/dist/gateway/inbox.d.ts.map +1 -1
  99. package/dist/gateway/inbox.js.map +1 -1
  100. package/dist/gateway/platform-config.d.ts +14 -0
  101. package/dist/gateway/platform-config.d.ts.map +1 -1
  102. package/dist/gateway/platform-config.js +26 -8
  103. package/dist/gateway/platform-config.js.map +1 -1
  104. package/dist/gateway/realtime.d.ts +114 -0
  105. package/dist/gateway/realtime.d.ts.map +1 -0
  106. package/dist/gateway/realtime.js +402 -0
  107. package/dist/gateway/realtime.js.map +1 -0
  108. package/dist/gateway/registry.d.ts +31 -0
  109. package/dist/gateway/registry.d.ts.map +1 -1
  110. package/dist/gateway/registry.js +224 -4
  111. package/dist/gateway/registry.js.map +1 -1
  112. package/dist/gateway/whatsapp/baileys-bridge.d.ts +11 -1
  113. package/dist/gateway/whatsapp/baileys-bridge.d.ts.map +1 -1
  114. package/dist/gateway/whatsapp/baileys-bridge.js +123 -4
  115. package/dist/gateway/whatsapp/baileys-bridge.js.map +1 -1
  116. package/dist/gateway/whatsapp/bridge.d.ts +6 -2
  117. package/dist/gateway/whatsapp/bridge.d.ts.map +1 -1
  118. package/dist/gateway/whatsapp/bridge.js.map +1 -1
  119. package/dist/index.js +8 -0
  120. package/dist/index.js.map +1 -1
  121. package/dist/inference/factory.d.ts +14 -0
  122. package/dist/inference/factory.d.ts.map +1 -1
  123. package/dist/inference/factory.js +17 -0
  124. package/dist/inference/factory.js.map +1 -1
  125. package/dist/inference/groq-adapter.d.ts +2 -0
  126. package/dist/inference/groq-adapter.d.ts.map +1 -1
  127. package/dist/inference/groq-adapter.js +16 -6
  128. package/dist/inference/groq-adapter.js.map +1 -1
  129. package/dist/inference/tools.d.ts.map +1 -1
  130. package/dist/inference/tools.js +29 -0
  131. package/dist/inference/tools.js.map +1 -1
  132. package/dist/learning/benchmark.d.ts.map +1 -1
  133. package/dist/learning/benchmark.js +3 -2
  134. package/dist/learning/benchmark.js.map +1 -1
  135. package/dist/learning/continuation.d.ts.map +1 -1
  136. package/dist/learning/continuation.js +2 -1
  137. package/dist/learning/continuation.js.map +1 -1
  138. package/dist/learning/cost-tracker.d.ts.map +1 -1
  139. package/dist/learning/cost-tracker.js +2 -1
  140. package/dist/learning/cost-tracker.js.map +1 -1
  141. package/dist/learning/deferred-task.d.ts.map +1 -1
  142. package/dist/learning/deferred-task.js +13 -4
  143. package/dist/learning/deferred-task.js.map +1 -1
  144. package/dist/learning/eval-framework.d.ts.map +1 -1
  145. package/dist/learning/eval-framework.js +2 -1
  146. package/dist/learning/eval-framework.js.map +1 -1
  147. package/dist/learning/long-form.d.ts.map +1 -1
  148. package/dist/learning/long-form.js +2 -1
  149. package/dist/learning/long-form.js.map +1 -1
  150. package/dist/learning/model-registry.d.ts.map +1 -1
  151. package/dist/learning/model-registry.js +2 -1
  152. package/dist/learning/model-registry.js.map +1 -1
  153. package/dist/learning/reasoning-cache.d.ts.map +1 -1
  154. package/dist/learning/reasoning-cache.js +2 -1
  155. package/dist/learning/reasoning-cache.js.map +1 -1
  156. package/dist/learning/reasoning-trace.d.ts +37 -1
  157. package/dist/learning/reasoning-trace.d.ts.map +1 -1
  158. package/dist/learning/reasoning-trace.js +66 -0
  159. package/dist/learning/reasoning-trace.js.map +1 -1
  160. package/dist/learning/resilient-call.d.ts.map +1 -1
  161. package/dist/learning/resilient-call.js +2 -1
  162. package/dist/learning/resilient-call.js.map +1 -1
  163. package/dist/learning/retrieval.d.ts.map +1 -1
  164. package/dist/learning/retrieval.js +2 -1
  165. package/dist/learning/retrieval.js.map +1 -1
  166. package/dist/learning/seeded-benchmark.d.ts +160 -0
  167. package/dist/learning/seeded-benchmark.d.ts.map +1 -0
  168. package/dist/learning/seeded-benchmark.js +321 -0
  169. package/dist/learning/seeded-benchmark.js.map +1 -0
  170. package/dist/learning/seeded-bugs.d.ts +142 -0
  171. package/dist/learning/seeded-bugs.d.ts.map +1 -0
  172. package/dist/learning/seeded-bugs.js +535 -0
  173. package/dist/learning/seeded-bugs.js.map +1 -0
  174. package/dist/learning/step-checkpoint.d.ts +127 -0
  175. package/dist/learning/step-checkpoint.d.ts.map +1 -0
  176. package/dist/learning/step-checkpoint.js +244 -0
  177. package/dist/learning/step-checkpoint.js.map +1 -0
  178. package/dist/nlu/intent-confirm.d.ts +23 -1
  179. package/dist/nlu/intent-confirm.d.ts.map +1 -1
  180. package/dist/nlu/intent-confirm.js +85 -2
  181. package/dist/nlu/intent-confirm.js.map +1 -1
  182. package/dist/nlu/learnings.d.ts +7 -0
  183. package/dist/nlu/learnings.d.ts.map +1 -1
  184. package/dist/nlu/learnings.js +7 -0
  185. package/dist/nlu/learnings.js.map +1 -1
  186. package/dist/observability/debug-log.d.ts +250 -0
  187. package/dist/observability/debug-log.d.ts.map +1 -0
  188. package/dist/observability/debug-log.js +500 -0
  189. package/dist/observability/debug-log.js.map +1 -0
  190. package/dist/observability/event-bus.d.ts.map +1 -1
  191. package/dist/observability/event-bus.js +4 -1
  192. package/dist/observability/event-bus.js.map +1 -1
  193. package/dist/observability/otel.d.ts +278 -0
  194. package/dist/observability/otel.d.ts.map +1 -0
  195. package/dist/observability/otel.js +590 -0
  196. package/dist/observability/otel.js.map +1 -0
  197. package/dist/parity/drivers.d.ts +99 -0
  198. package/dist/parity/drivers.d.ts.map +1 -0
  199. package/dist/parity/drivers.js +1362 -0
  200. package/dist/parity/drivers.js.map +1 -0
  201. package/dist/parity/graph.d.ts +73 -0
  202. package/dist/parity/graph.d.ts.map +1 -0
  203. package/dist/parity/graph.js +162 -0
  204. package/dist/parity/graph.js.map +1 -0
  205. package/dist/parity/matrix.d.ts +105 -0
  206. package/dist/parity/matrix.d.ts.map +1 -0
  207. package/dist/parity/matrix.js +352 -0
  208. package/dist/parity/matrix.js.map +1 -0
  209. package/dist/parity/observation.d.ts +444 -0
  210. package/dist/parity/observation.d.ts.map +1 -0
  211. package/dist/parity/observation.js +333 -0
  212. package/dist/parity/observation.js.map +1 -0
  213. package/dist/parity/scenarios.d.ts +229 -0
  214. package/dist/parity/scenarios.d.ts.map +1 -0
  215. package/dist/parity/scenarios.js +175 -0
  216. package/dist/parity/scenarios.js.map +1 -0
  217. package/dist/parity/surfaces.d.ts +122 -0
  218. package/dist/parity/surfaces.d.ts.map +1 -0
  219. package/dist/parity/surfaces.js +190 -0
  220. package/dist/parity/surfaces.js.map +1 -0
  221. package/dist/runtime/fault-injection.d.ts +173 -0
  222. package/dist/runtime/fault-injection.d.ts.map +1 -0
  223. package/dist/runtime/fault-injection.js +281 -0
  224. package/dist/runtime/fault-injection.js.map +1 -0
  225. package/dist/tools/child-agent-entry.d.ts +23 -0
  226. package/dist/tools/child-agent-entry.d.ts.map +1 -0
  227. package/dist/tools/child-agent-entry.js +129 -0
  228. package/dist/tools/child-agent-entry.js.map +1 -0
  229. package/dist/tools/child-agent-runtime.d.ts +124 -0
  230. package/dist/tools/child-agent-runtime.d.ts.map +1 -0
  231. package/dist/tools/child-agent-runtime.js +704 -0
  232. package/dist/tools/child-agent-runtime.js.map +1 -0
  233. package/dist/tools/coding-tools.d.ts.map +1 -1
  234. package/dist/tools/coding-tools.js +82 -10
  235. package/dist/tools/coding-tools.js.map +1 -1
  236. package/dist/tools/delegation-system.d.ts +31 -0
  237. package/dist/tools/delegation-system.d.ts.map +1 -1
  238. package/dist/tools/delegation-system.js +70 -9
  239. package/dist/tools/delegation-system.js.map +1 -1
  240. package/dist/tools/extract/docx.d.ts +27 -0
  241. package/dist/tools/extract/docx.d.ts.map +1 -0
  242. package/dist/tools/extract/docx.js +48 -0
  243. package/dist/tools/extract/docx.js.map +1 -0
  244. package/dist/tools/extract/html-text.d.ts +27 -0
  245. package/dist/tools/extract/html-text.d.ts.map +1 -0
  246. package/dist/tools/extract/html-text.js +86 -0
  247. package/dist/tools/extract/html-text.js.map +1 -0
  248. package/dist/tools/extract/pdf-ocr.d.ts +58 -0
  249. package/dist/tools/extract/pdf-ocr.d.ts.map +1 -0
  250. package/dist/tools/extract/pdf-ocr.js +116 -0
  251. package/dist/tools/extract/pdf-ocr.js.map +1 -0
  252. package/dist/tools/extract/pdf.d.ts +65 -0
  253. package/dist/tools/extract/pdf.d.ts.map +1 -0
  254. package/dist/tools/extract/pdf.js +197 -0
  255. package/dist/tools/extract/pdf.js.map +1 -0
  256. package/dist/tools/extract/pptx.d.ts +32 -0
  257. package/dist/tools/extract/pptx.d.ts.map +1 -0
  258. package/dist/tools/extract/pptx.js +77 -0
  259. package/dist/tools/extract/pptx.js.map +1 -0
  260. package/dist/tools/extract/xlsx.d.ts +47 -0
  261. package/dist/tools/extract/xlsx.d.ts.map +1 -0
  262. package/dist/tools/extract/xlsx.js +111 -0
  263. package/dist/tools/extract/xlsx.js.map +1 -0
  264. package/dist/tools/finding-tool.d.ts +76 -0
  265. package/dist/tools/finding-tool.d.ts.map +1 -0
  266. package/dist/tools/finding-tool.js +125 -0
  267. package/dist/tools/finding-tool.js.map +1 -0
  268. package/dist/tools/messaging-tools.d.ts +41 -11
  269. package/dist/tools/messaging-tools.d.ts.map +1 -1
  270. package/dist/tools/messaging-tools.js +104 -55
  271. package/dist/tools/messaging-tools.js.map +1 -1
  272. package/dist/tools/neutts-synth.d.ts +27 -3
  273. package/dist/tools/neutts-synth.d.ts.map +1 -1
  274. package/dist/tools/neutts-synth.js +57 -13
  275. package/dist/tools/neutts-synth.js.map +1 -1
  276. package/dist/tools/pipeline-tool.d.ts +43 -1
  277. package/dist/tools/pipeline-tool.d.ts.map +1 -1
  278. package/dist/tools/pipeline-tool.js +13 -2
  279. package/dist/tools/pipeline-tool.js.map +1 -1
  280. package/dist/tools/read-extract.d.ts +116 -45
  281. package/dist/tools/read-extract.d.ts.map +1 -1
  282. package/dist/tools/read-extract.js +494 -158
  283. package/dist/tools/read-extract.js.map +1 -1
  284. package/dist/tools/registry.d.ts +2 -2
  285. package/dist/tools/registry.d.ts.map +1 -1
  286. package/dist/tools/registry.js +152 -23
  287. package/dist/tools/registry.js.map +1 -1
  288. package/dist/tools/subagent-refusal.d.ts +15 -0
  289. package/dist/tools/subagent-refusal.d.ts.map +1 -0
  290. package/dist/tools/subagent-refusal.js +18 -0
  291. package/dist/tools/subagent-refusal.js.map +1 -0
  292. package/dist/tools/subagent-spawner.d.ts +122 -0
  293. package/dist/tools/subagent-spawner.d.ts.map +1 -1
  294. package/dist/tools/subagent-spawner.js +249 -28
  295. package/dist/tools/subagent-spawner.js.map +1 -1
  296. package/dist/tools/tool-hooks.d.ts +177 -0
  297. package/dist/tools/tool-hooks.d.ts.map +1 -0
  298. package/dist/tools/tool-hooks.js +427 -0
  299. package/dist/tools/tool-hooks.js.map +1 -0
  300. package/dist/tools/tool-loop.d.ts +82 -0
  301. package/dist/tools/tool-loop.d.ts.map +1 -1
  302. package/dist/tools/tool-loop.js +167 -9
  303. package/dist/tools/tool-loop.js.map +1 -1
  304. package/dist/tools/tool-refusal.d.ts +68 -0
  305. package/dist/tools/tool-refusal.d.ts.map +1 -0
  306. package/dist/tools/tool-refusal.js +78 -0
  307. package/dist/tools/tool-refusal.js.map +1 -0
  308. package/dist/tools/toolsets.d.ts +8 -0
  309. package/dist/tools/toolsets.d.ts.map +1 -1
  310. package/dist/tools/toolsets.js +12 -2
  311. package/dist/tools/toolsets.js.map +1 -1
  312. package/dist/tools/vision-tools.d.ts +88 -83
  313. package/dist/tools/vision-tools.d.ts.map +1 -1
  314. package/dist/tools/vision-tools.js +134 -103
  315. package/dist/tools/vision-tools.js.map +1 -1
  316. package/dist/tools/worktree.d.ts +210 -0
  317. package/dist/tools/worktree.d.ts.map +1 -0
  318. package/dist/tools/worktree.js +374 -0
  319. package/dist/tools/worktree.js.map +1 -0
  320. package/dist/utils/format.d.ts +3 -0
  321. package/dist/utils/format.d.ts.map +1 -0
  322. package/dist/utils/format.js +32 -0
  323. package/dist/utils/format.js.map +1 -0
  324. package/dist/web-dashboard/attachment-extract.d.ts +64 -0
  325. package/dist/web-dashboard/attachment-extract.d.ts.map +1 -0
  326. package/dist/web-dashboard/attachment-extract.js +154 -0
  327. package/dist/web-dashboard/attachment-extract.js.map +1 -0
  328. package/dist/web-dashboard/chat-console.d.ts +108 -1
  329. package/dist/web-dashboard/chat-console.d.ts.map +1 -1
  330. package/dist/web-dashboard/chat-console.js +36 -0
  331. package/dist/web-dashboard/chat-console.js.map +1 -1
  332. package/dist/web-dashboard/hub-data.d.ts +37 -0
  333. package/dist/web-dashboard/hub-data.d.ts.map +1 -1
  334. package/dist/web-dashboard/hub-data.js +61 -1
  335. package/dist/web-dashboard/hub-data.js.map +1 -1
  336. package/dist/web-dashboard/server.d.ts +14 -0
  337. package/dist/web-dashboard/server.d.ts.map +1 -1
  338. package/dist/web-dashboard/server.js +247 -13
  339. package/dist/web-dashboard/server.js.map +1 -1
  340. package/dist/web-dashboard/src/types.d.ts +196 -48
  341. package/dist/web-dashboard/src/types.d.ts.map +1 -1
  342. package/package.json +18 -3
  343. package/src/web-dashboard/public/assets/{index-Cyd6tIew.css → index-XJjj2cBX.css} +1 -1
  344. package/src/web-dashboard/public/assets/index-YWF9FpwQ.js +207 -0
  345. package/src/web-dashboard/public/assets/index-YWF9FpwQ.js.map +1 -0
  346. package/src/web-dashboard/public/index.html +2 -2
  347. package/dist/tools/child-agent-worker.js +0 -212
  348. package/src/web-dashboard/public/assets/index-CxDj7p6i.js +0 -207
  349. package/src/web-dashboard/public/assets/index-CxDj7p6i.js.map +0 -1
@@ -1,32 +1,83 @@
1
1
  /**
2
2
  * I2 — Hook registry (`src/gateway/hooks.ts`).
3
3
  *
4
- * Lifecycle hooks the agent
5
- * runtime fires at well-defined moments. Two events today (extensible):
4
+ * Lifecycle hooks the agent runtime fires at well-defined moments. The tool
5
+ * phases are the WS4 (#26) triple, in the order a call goes through them:
6
6
  *
7
- * - `post_tool_call` — after the tool loop executes a registry tool. Driven
8
- * by the `tool:called` event-bus event emitted from `src/tools/tool-loop.ts`
9
- * (the `post_tool_call` hook). Handlers receive the tool name,
10
- * result, success flag and duration.
11
- * - `on_session_end` — after a pipeline run finishes (execute:completed /
12
- * execute:failed). Handlers receive the run's success + summary.
7
+ * - `before_tool_call` — BEFORE the call runs, and the ONLY phase that can stop
8
+ * it: a handler returns a {@link HookDecision} and the call is not made.
9
+ * - `after_tool_call` — the call ran and succeeded. Handlers receive the tool
10
+ * name, the result, the success flag and the duration.
11
+ * - `failed_tool_call` — the call ran and did NOT succeed (a thrown error, or a
12
+ * result the loop`s own convention marks as a failure).
13
+ * - `on_session_end` — after a pipeline run finishes (execute:completed /
14
+ * execute:failed). Handlers receive the run`s success + summary.
13
15
  *
14
- * Wiring is through the EXISTING observability event bus — hooks are typed
15
- * consumers, not a parallel system. `installHooks(bus)` subscribes and returns
16
- * an unsubscribe; the default built-in hook logs session summaries.
16
+ * `post_tool_call` was this event`s previous name. It is renamed rather than
17
+ * aliased so the three phases read exactly as the capability is stated
18
+ * (before/after/failed); nothing in production subscribed to it, and an alias
19
+ * would leave two names for one moment — the drift this repo removes elsewhere.
20
+ *
21
+ * THE TOOL PHASES ARE DRIVEN BY THE EXECUTION SEAM, not the event bus, and that
22
+ * is a deliberate reversal of the original wiring. A bus subscription is
23
+ * fire-and-forget: it cannot stop a call, it cannot tell the loop what a
24
+ * subscriber decided, and it only fires on a surface that happens to put
25
+ * `tool:called` on the bus — so a hook installed that way reached the gateway and
26
+ * nowhere else. `src/tools/tool-loop.ts` and `src/tools/child-agent-runtime.ts`
27
+ * call {@link HookRegistry.runBefore} / {@link HookRegistry.run} directly, which
28
+ * is what makes the hooks fire on all five surfaces and lets a veto be honoured.
29
+ */
30
+ export type HookEvent = 'before_tool_call' | 'after_tool_call' | 'failed_tool_call' | 'on_session_end';
31
+ /**
32
+ * What a `before_tool_call` handler may return to stop the call.
33
+ *
34
+ * A RETURN VALUE rather than a mutation, because the registry has to hand the
35
+ * decision back to the caller that is about to run the tool: a subscriber that
36
+ * could only observe could not veto.
37
+ */
38
+ export interface HookDecision {
39
+ /** `true` stops the call. There is no "deny: false" — an absent decision allows. */
40
+ deny: true;
41
+ /** Why, in the operator's words. Flows to the model and to the turn's trace. */
42
+ reason?: string;
43
+ /** Which hook decided (a declaration label, or a subscriber's own name). */
44
+ by?: string;
45
+ }
46
+ /**
47
+ * The call itself, as every tool phase sees it.
48
+ *
49
+ * `report` is how a subscriber says something went wrong in its OWN handling.
50
+ * It exists because the seam FAILS OPEN: a broken hook must not block work, so if
51
+ * there were no way to report one, a hook that silently stopped working would be
52
+ * indistinguishable from a hook that allowed everything.
17
53
  */
18
- export type HookEvent = 'post_tool_call' | 'on_session_end';
19
- /** Context for `post_tool_call` handlers. */
20
- export interface ToolCallHookContext {
54
+ export interface ToolCallRef {
21
55
  tool: string;
56
+ /** The call's arguments, as the model produced them. */
57
+ args?: Record<string, unknown>;
58
+ /** The provider's call id, when there is one. */
59
+ callId?: string;
60
+ /** The surface label the turn declared (`cli-chat`, `subagent`, …). */
61
+ surface?: string;
62
+ cwd?: string;
63
+ report?: (message: string) => void;
64
+ }
65
+ /** Context for `after_tool_call` handlers. */
66
+ export interface ToolCallHookContext extends ToolCallRef {
22
67
  ok: boolean;
23
68
  /** The tool-result text fed back to the model (truncated for hooks). */
24
69
  result?: string;
25
- /** Error text when the tool failed. */
26
- error?: string;
27
70
  /** Execution duration in ms. */
28
71
  durationMs?: number;
29
72
  }
73
+ /** Context for `failed_tool_call` handlers. */
74
+ export interface FailedToolCallHookContext extends ToolCallRef {
75
+ /** Why it failed — the thrown message, or the failing result's own text. */
76
+ error: string;
77
+ /** The result text, when the tool returned a failure rather than throwing. */
78
+ result?: string;
79
+ durationMs?: number;
80
+ }
30
81
  /** Context for `on_session_end` handlers. */
31
82
  export interface SessionEndHookContext {
32
83
  success: boolean;
@@ -34,8 +85,14 @@ export interface SessionEndHookContext {
34
85
  /** The pipeline goal when known. */
35
86
  goal?: string;
36
87
  }
37
- /** A hook handler — sync or async; the registry runs them serially. */
38
- export type HookHandler<T> = (ctx: T) => void | Promise<void>;
88
+ /**
89
+ * A hook handler — sync or async; the registry runs them serially.
90
+ *
91
+ * A returned {@link HookDecision} is honoured for `before_tool_call` (the only
92
+ * phase where stopping the call is possible) and ignored elsewhere, so one
93
+ * handler type serves the whole registry.
94
+ */
95
+ export type HookHandler<T> = (ctx: T) => void | HookDecision | Promise<void | HookDecision>;
39
96
  declare class HookRegistry {
40
97
  private handlers;
41
98
  /** Register a handler for a hook event. Idempotent per (event, fn) pair. */
@@ -44,10 +101,21 @@ declare class HookRegistry {
44
101
  unregister<T extends HookEvent>(event: T, handler: HookHandler<HookContextFor<T>>): void;
45
102
  /** Run every handler for an event, serially, best-effort (never throws). */
46
103
  run<T extends HookEvent>(event: T, ctx: HookContextFor<T>): Promise<void>;
104
+ /**
105
+ * Run the `before_tool_call` handlers and return the FIRST decision.
106
+ *
107
+ * Serial by construction: two hooks must not race over whether a call happens,
108
+ * and the first denial is the answer — a later hook cannot un-deny a call that
109
+ * has already been stopped. A handler that throws is reported and skipped
110
+ * (FAIL OPEN), so one broken hook cannot stop every tool call in the process.
111
+ */
112
+ runBefore(ctx: BeforeToolCallHookContext): Promise<HookDecision | null>;
47
113
  /** Registered handler counts per event (CLI/tests introspection). */
48
114
  list(): Record<HookEvent, number>;
49
115
  }
50
- type HookContextFor<T extends HookEvent> = T extends 'post_tool_call' ? ToolCallHookContext : SessionEndHookContext;
116
+ /** Context for `before_tool_call` handlers: the call, before it happens. */
117
+ export type BeforeToolCallHookContext = ToolCallRef;
118
+ type HookContextFor<T extends HookEvent> = T extends 'before_tool_call' ? BeforeToolCallHookContext : T extends 'after_tool_call' ? ToolCallHookContext : T extends 'failed_tool_call' ? FailedToolCallHookContext : SessionEndHookContext;
51
119
  /** The singleton registry. */
52
120
  export declare const hooks: HookRegistry;
53
121
  /** Wire the registry to the event bus. Returns an unsubscribe function. */
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/gateway/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAOH,MAAM,MAAM,SAAS,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;AAE5D,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,6CAA6C;AAC7C,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,uEAAuE;AACvE,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAI9D,cAAM,YAAY;IAChB,OAAO,CAAC,QAAQ,CAAiD;IAEjE,4EAA4E;IAC5E,QAAQ,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAMtF,4EAA4E;IAC5E,UAAU,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAQxF,4EAA4E;IACtE,GAAG,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAU/E,qEAAqE;IACrE,IAAI,IAAI,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC;CAMlC;AAED,KAAK,cAAc,CAAC,CAAC,SAAS,SAAS,IAAI,CAAC,SAAS,gBAAgB,GACjE,mBAAmB,GACnB,qBAAqB,CAAC;AAE1B,8BAA8B;AAC9B,eAAO,MAAM,KAAK,cAAqB,CAAC;AAIxC,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,GAAG,iCAAgB,GAAG,MAAM,IAAI,CA0C5D;AAID;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAQ3C"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/gateway/hooks.ts"],"names":[],"mappings":"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"}
@@ -1,19 +1,31 @@
1
1
  /**
2
2
  * I2 — Hook registry (`src/gateway/hooks.ts`).
3
3
  *
4
- * Lifecycle hooks the agent
5
- * runtime fires at well-defined moments. Two events today (extensible):
4
+ * Lifecycle hooks the agent runtime fires at well-defined moments. The tool
5
+ * phases are the WS4 (#26) triple, in the order a call goes through them:
6
6
  *
7
- * - `post_tool_call` — after the tool loop executes a registry tool. Driven
8
- * by the `tool:called` event-bus event emitted from `src/tools/tool-loop.ts`
9
- * (the `post_tool_call` hook). Handlers receive the tool name,
10
- * result, success flag and duration.
11
- * - `on_session_end` — after a pipeline run finishes (execute:completed /
12
- * execute:failed). Handlers receive the run's success + summary.
7
+ * - `before_tool_call` — BEFORE the call runs, and the ONLY phase that can stop
8
+ * it: a handler returns a {@link HookDecision} and the call is not made.
9
+ * - `after_tool_call` — the call ran and succeeded. Handlers receive the tool
10
+ * name, the result, the success flag and the duration.
11
+ * - `failed_tool_call` — the call ran and did NOT succeed (a thrown error, or a
12
+ * result the loop`s own convention marks as a failure).
13
+ * - `on_session_end` — after a pipeline run finishes (execute:completed /
14
+ * execute:failed). Handlers receive the run`s success + summary.
13
15
  *
14
- * Wiring is through the EXISTING observability event bus — hooks are typed
15
- * consumers, not a parallel system. `installHooks(bus)` subscribes and returns
16
- * an unsubscribe; the default built-in hook logs session summaries.
16
+ * `post_tool_call` was this event`s previous name. It is renamed rather than
17
+ * aliased so the three phases read exactly as the capability is stated
18
+ * (before/after/failed); nothing in production subscribed to it, and an alias
19
+ * would leave two names for one moment — the drift this repo removes elsewhere.
20
+ *
21
+ * THE TOOL PHASES ARE DRIVEN BY THE EXECUTION SEAM, not the event bus, and that
22
+ * is a deliberate reversal of the original wiring. A bus subscription is
23
+ * fire-and-forget: it cannot stop a call, it cannot tell the loop what a
24
+ * subscriber decided, and it only fires on a surface that happens to put
25
+ * `tool:called` on the bus — so a hook installed that way reached the gateway and
26
+ * nowhere else. `src/tools/tool-loop.ts` and `src/tools/child-agent-runtime.ts`
27
+ * call {@link HookRegistry.runBefore} / {@link HookRegistry.run} directly, which
28
+ * is what makes the hooks fire on all five surfaces and lets a veto be honoured.
17
29
  */
18
30
  import { logger } from '../utils/logger.js';
19
31
  import { getEventBus, EventNames } from '../observability/event-bus.js';
@@ -45,14 +57,46 @@ class HookRegistry {
45
57
  await handler(ctx);
46
58
  }
47
59
  catch (err) {
48
- logger.debug(`hook '${event}' handler failed: ${err instanceof Error ? err.message : err}`);
60
+ const message = `hook '${event}' handler failed: ${err instanceof Error ? err.message : err}`;
61
+ // Told to the CALLER as well as the log, because a handler that throws is
62
+ // fail-open: without this, a broken subscriber is indistinguishable from
63
+ // one that approved.
64
+ ctx.report?.(message);
65
+ logger.debug(message);
66
+ }
67
+ }
68
+ }
69
+ /**
70
+ * Run the `before_tool_call` handlers and return the FIRST decision.
71
+ *
72
+ * Serial by construction: two hooks must not race over whether a call happens,
73
+ * and the first denial is the answer — a later hook cannot un-deny a call that
74
+ * has already been stopped. A handler that throws is reported and skipped
75
+ * (FAIL OPEN), so one broken hook cannot stop every tool call in the process.
76
+ */
77
+ async runBefore(ctx) {
78
+ for (const handler of this.handlers.get('before_tool_call') ?? []) {
79
+ let decision;
80
+ try {
81
+ decision = await handler(ctx);
82
+ }
83
+ catch (err) {
84
+ const message = `hook 'before_tool_call' handler failed: ${err instanceof Error ? err.message : err}`;
85
+ ctx.report?.(message);
86
+ logger.debug(message);
87
+ continue;
49
88
  }
89
+ if (decision && decision.deny)
90
+ return decision;
50
91
  }
92
+ return null;
51
93
  }
52
94
  /** Registered handler counts per event (CLI/tests introspection). */
53
95
  list() {
54
96
  return {
55
- post_tool_call: this.handlers.get('post_tool_call')?.length ?? 0,
97
+ before_tool_call: this.handlers.get('before_tool_call')?.length ?? 0,
98
+ after_tool_call: this.handlers.get('after_tool_call')?.length ?? 0,
99
+ failed_tool_call: this.handlers.get('failed_tool_call')?.length ?? 0,
56
100
  on_session_end: this.handlers.get('on_session_end')?.length ?? 0,
57
101
  };
58
102
  }
@@ -63,16 +107,11 @@ export const hooks = new HookRegistry();
63
107
  /** Wire the registry to the event bus. Returns an unsubscribe function. */
64
108
  export function installHooks(bus = getEventBus()) {
65
109
  const unsubscribers = [];
66
- unsubscribers.push(bus.on(EventNames.TOOL_CALLED, (record) => {
67
- const d = (record.data ?? {});
68
- void hooks.run('post_tool_call', {
69
- tool: d.tool ?? 'unknown',
70
- ok: d.ok !== false,
71
- result: typeof d.result === 'string' ? d.result.slice(0, 500) : undefined,
72
- error: d.error,
73
- durationMs: d.durationMs,
74
- });
75
- }));
110
+ // NOTE: there is deliberately no `tool:called` subscription here any more. The
111
+ // tool phases are driven by the execution seam (see the module header), and a
112
+ // bus subscription would fire every tool hook a SECOND time on any surface
113
+ // that puts the event on the bus — which is the kind of double-fire nobody
114
+ // notices until a hook has an external side effect.
76
115
  unsubscribers.push(bus.on(EventNames.EXECUTE_COMPLETED, (record) => {
77
116
  const d = (record.data ?? {});
78
117
  void hooks.run('on_session_end', {
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/gateway/hooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/gateway/hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Inbound document hydration for the gateway (`src/gateway/inbound-media.ts`).
3
+ *
4
+ * A messaging transport delivers a DOCUMENT (a PDF report, a DOCX contract, a
5
+ * spreadsheet) as bytes + a filename — never as text. The bridge only extracted
6
+ * `conversation` / `extendedTextMessage`, so a document message arrived with an
7
+ * empty `text` and was dropped at `if (!text) continue`: the sender's own file
8
+ * vanished with no reply and no record.
9
+ *
10
+ * This module is the fix for the inbound half of that gap. The bridge DOWNLOADS
11
+ * the bytes, they ride on `InboundMessage.media`, and `handleInbound` calls
12
+ * `hydrateInboundMedia` — which writes them to the artifact sandbox and runs the
13
+ * SAME `read_extract` the agent uses for a file in the project folder. The
14
+ * returned section is prepended to the turn's text, so a caption + a document
15
+ * becomes one request the model can act on.
16
+ *
17
+ * Extraction (not the download) is what makes the file usable: a document whose
18
+ * bytes never become text is still a message the agent cannot answer. When the
19
+ * file cannot be extracted the section says so, with the typed code and the
20
+ * concrete alternatives `read_extract` produces — never a silent empty result.
21
+ *
22
+ * Never throws: a media failure must not break the text turn it arrived with.
23
+ */
24
+ /** A media attachment that rode in on an inbound message. */
25
+ export interface InboundMedia {
26
+ type: 'image' | 'video' | 'audio' | 'document';
27
+ /** The file's bytes (already downloaded by the transport). */
28
+ data: Uint8Array;
29
+ /** The sender's filename, when the transport provides one. */
30
+ filename?: string;
31
+ /** MIME type, when the transport provides one. */
32
+ mimetype?: string;
33
+ /** The transport's caption on the media message (may carry the instruction). */
34
+ caption?: string;
35
+ }
36
+ /** What we are willing to write + extract in one inbound turn. */
37
+ export declare const MAX_INBOUND_MEDIA_BYTES: number;
38
+ /** How long an extracted inbound attachment is kept before the sweep (ms). */
39
+ export declare const INBOUND_MEDIA_TTL_MS: number;
40
+ /**
41
+ * Sandbox size cap (bytes). Past this, the OLDEST remaining files are swept
42
+ * even if they are still inside the TTL — a long-running gateway fed scanned
43
+ * reports should not grow without bound.
44
+ */
45
+ export declare const INBOUND_MEDIA_MAX_BYTES: number;
46
+ /**
47
+ * Reduce a sender-supplied name to a safe basename that keeps its extension —
48
+ * the name is untrusted and must never escape the artifact dir.
49
+ */
50
+ export declare function safeInboundName(media: InboundMedia): string;
51
+ /** A document that arrived but could not be turned into text. */
52
+ export interface InboundMediaFailure {
53
+ /** The attachment's display name. */
54
+ name: string;
55
+ /** The media kind (only 'document' triggers the sender reply — see below). */
56
+ type: InboundMedia['type'];
57
+ /** A short, sender-safe reason (no stack traces, no not artifact paths). */
58
+ reason: string;
59
+ }
60
+ /** The outcome of hydrating one inbound attachment. */
61
+ export interface HydratedInboundMedia {
62
+ /**
63
+ * The labelled context section to prepend to the turn, or null when there is
64
+ * nothing to add. Never null in practice: extracted text, an image note, or a
65
+ * refusal note all produce a section.
66
+ */
67
+ section: string | null;
68
+ /**
69
+ * Set when a DOCUMENT arrived but could not be turned into text. The registry
70
+ * auto-replies with this to the sender — a document that produces no text and
71
+ * no reply is precisely the failure this whole path exists to remove.
72
+ */
73
+ failure?: InboundMediaFailure;
74
+ }
75
+ /**
76
+ * Render the sender-facing reply for a document that could not be extracted.
77
+ *
78
+ * Built from `reason` alone on purpose: the model-facing section carries the
79
+ * saved artifact path and agent-jargon alternatives (`call read_extract again
80
+ * with ocr:true`), neither of which belongs in a chat with the person who sent
81
+ * the file.
82
+ */
83
+ export declare function formatMediaFailureReply(failure: InboundMediaFailure): string;
84
+ /**
85
+ * Extract an inbound media attachment into a labelled context section. Never
86
+ * throws — a failure is reported as `failure` (plus a refusal section) instead.
87
+ *
88
+ * The saved path is always included so the model can follow up on the ORIGINAL
89
+ * file (e.g. `read_extract` with `ocr:true` for a scanned PDF, or
90
+ * `describe_image` for an image) instead of only seeing the extracted text.
91
+ */
92
+ export declare function hydrateInboundMedia(media: InboundMedia, opts?: {
93
+ maxBytes?: number;
94
+ }): Promise<HydratedInboundMedia>;
95
+ /** The effective inbound-attachment policy (config `gateway.inboundAttachments`). */
96
+ export interface InboundAttachmentPolicy {
97
+ /** When false, attachments are accepted but never downloaded or extracted. */
98
+ enabled: boolean;
99
+ /** Per-attachment byte cap (default MAX_INBOUND_MEDIA_BYTES). */
100
+ maxBytes: number;
101
+ }
102
+ /**
103
+ * Read the effective inbound-attachment policy from config. Never throws — an
104
+ * absent config (or a throwing ConfigManager) means the safe default: enabled,
105
+ * with the module's own cap.
106
+ */
107
+ export declare function inboundAttachmentPolicy(cm?: {
108
+ getAll?: () => unknown;
109
+ }): InboundAttachmentPolicy;
110
+ /** A remote attachment to fetch before hydration (Discord CDN URL / Slack file). */
111
+ export interface RemoteAttachment {
112
+ /** The attachment's media kind (already classified by the caller). */
113
+ type: InboundMedia['type'];
114
+ url: string;
115
+ filename?: string;
116
+ mimetype?: string;
117
+ size?: number;
118
+ /** True when fetching the URL needs an Authorization bearer token (Slack). */
119
+ authenticated?: boolean;
120
+ /** The token to send when `authenticated` (the caller supplies its own). */
121
+ token?: string;
122
+ }
123
+ /**
124
+ * Download a remote attachment's bytes (never throws — null on any failure or
125
+ * an over-cap size). Shared by the webhook receiver and the real-time Discord
126
+ * gateway / Slack Socket Mode transports, so one code path fetches every
127
+ * inbound attachment.
128
+ */
129
+ export declare function downloadInboundAttachment(att: RemoteAttachment): Promise<InboundMedia | null>;
130
+ /** What a sandbox sweep did (returned for the caller's log line). */
131
+ export interface InboundPruneResult {
132
+ removed: number;
133
+ bytesFreed: number;
134
+ kept: number;
135
+ }
136
+ /**
137
+ * Sweep the inbound artifact sandbox: remove files older than `maxAgeMs`, then
138
+ * (if still over `maxBytes`) the OLDEST of what remains until it fits. Safe to
139
+ * call on a schedule — never throws, and a file that cannot be removed is
140
+ * skipped rather than aborting the sweep.
141
+ */
142
+ export declare function pruneInboundMedia(opts?: {
143
+ maxAgeMs?: number;
144
+ maxBytes?: number;
145
+ now?: number;
146
+ }): InboundPruneResult;
147
+ //# sourceMappingURL=inbound-media.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound-media.d.ts","sourceRoot":"","sources":["../../src/gateway/inbound-media.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH,6DAA6D;AAC7D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,CAAC;IAC/C,8DAA8D;IAC9D,IAAI,EAAE,UAAU,CAAC;IACjB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,kEAAkE;AAClE,eAAO,MAAM,uBAAuB,QAAmB,CAAC;AAExD,8EAA8E;AAC9E,eAAO,MAAM,oBAAoB,QAA0B,CAAC;AAE5D;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,QAAoB,CAAC;AAkCzD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAO3D;AAwBD,iEAAiE;AACjE,MAAM,WAAW,mBAAmB;IAClC,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3B,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,uDAAuD;AACvD,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;;OAIG;IACH,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAM5E;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,YAAY,EACnB,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CA+E/B;AAED,qFAAqF;AACrF,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,OAAO,EAAE,OAAO,CAAC;IACjB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,OAAO,CAAA;CAAE,GAAG,uBAAuB,CAahG;AAED,oFAAoF;AACpF,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAgBnG;AAED,qEAAqE;AACrE,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAYD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAChE,kBAAkB,CAuDpB"}