@tai42/api-client 16.0.0 → 17.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/dist/agents.d.ts.map +1 -1
  2. package/dist/agents.js +1 -1
  3. package/dist/agents.js.map +1 -1
  4. package/dist/client/agents-client.d.ts +26 -0
  5. package/dist/client/agents-client.d.ts.map +1 -0
  6. package/dist/client/agents-client.js +19 -0
  7. package/dist/client/agents-client.js.map +1 -0
  8. package/dist/client/auth-client.d.ts +247 -0
  9. package/dist/client/auth-client.d.ts.map +1 -0
  10. package/dist/client/auth-client.js +73 -0
  11. package/dist/client/auth-client.js.map +1 -0
  12. package/dist/client/backend-client.d.ts +39 -0
  13. package/dist/client/backend-client.d.ts.map +1 -0
  14. package/dist/client/backend-client.js +22 -0
  15. package/dist/client/backend-client.js.map +1 -0
  16. package/dist/client/backup-client.d.ts +56 -0
  17. package/dist/client/backup-client.d.ts.map +1 -0
  18. package/dist/client/backup-client.js +12 -0
  19. package/dist/client/backup-client.js.map +1 -0
  20. package/dist/client/capabilities-client.d.ts +40 -0
  21. package/dist/client/capabilities-client.d.ts.map +1 -0
  22. package/dist/client/capabilities-client.js +19 -0
  23. package/dist/client/capabilities-client.js.map +1 -0
  24. package/dist/client/channels-client.d.ts +7 -0
  25. package/dist/client/channels-client.d.ts.map +1 -0
  26. package/dist/client/channels-client.js +10 -0
  27. package/dist/client/channels-client.js.map +1 -0
  28. package/dist/client/config-client.d.ts +59 -0
  29. package/dist/client/config-client.d.ts.map +1 -0
  30. package/dist/client/config-client.js +18 -0
  31. package/dist/client/config-client.js.map +1 -0
  32. package/dist/client/connectors-client.d.ts +225 -0
  33. package/dist/client/connectors-client.d.ts.map +1 -0
  34. package/dist/client/connectors-client.js +31 -0
  35. package/dist/client/connectors-client.js.map +1 -0
  36. package/dist/client/conversations-client.d.ts +398 -0
  37. package/dist/client/conversations-client.d.ts.map +1 -0
  38. package/dist/client/conversations-client.js +120 -0
  39. package/dist/client/conversations-client.js.map +1 -0
  40. package/dist/client/hooks-client.d.ts +112 -0
  41. package/dist/client/hooks-client.d.ts.map +1 -0
  42. package/dist/client/hooks-client.js +25 -0
  43. package/dist/client/hooks-client.js.map +1 -0
  44. package/dist/{client.d.ts → client/index.d.ts} +2336 -2708
  45. package/dist/client/index.d.ts.map +1 -0
  46. package/dist/client/index.js +79 -0
  47. package/dist/client/index.js.map +1 -0
  48. package/dist/client/interactions-client.d.ts +52 -0
  49. package/dist/client/interactions-client.d.ts.map +1 -0
  50. package/dist/client/interactions-client.js +84 -0
  51. package/dist/client/interactions-client.js.map +1 -0
  52. package/dist/client/login-client.d.ts +69 -0
  53. package/dist/client/login-client.d.ts.map +1 -0
  54. package/dist/client/login-client.js +137 -0
  55. package/dist/client/login-client.js.map +1 -0
  56. package/dist/client/manifest-client.d.ts +354 -0
  57. package/dist/client/manifest-client.d.ts.map +1 -0
  58. package/dist/client/manifest-client.js +76 -0
  59. package/dist/client/manifest-client.js.map +1 -0
  60. package/dist/client/marketplace-client.d.ts +274 -0
  61. package/dist/client/marketplace-client.d.ts.map +1 -0
  62. package/dist/client/marketplace-client.js +46 -0
  63. package/dist/client/marketplace-client.js.map +1 -0
  64. package/dist/client/mcp-config-schema-client.d.ts +5 -0
  65. package/dist/client/mcp-config-schema-client.d.ts.map +1 -0
  66. package/dist/client/mcp-config-schema-client.js +9 -0
  67. package/dist/client/mcp-config-schema-client.js.map +1 -0
  68. package/dist/client/notifications-client.d.ts +27 -0
  69. package/dist/client/notifications-client.d.ts.map +1 -0
  70. package/dist/client/notifications-client.js +11 -0
  71. package/dist/client/notifications-client.js.map +1 -0
  72. package/dist/client/observability-client.d.ts +103 -0
  73. package/dist/client/observability-client.d.ts.map +1 -0
  74. package/dist/client/observability-client.js +43 -0
  75. package/dist/client/observability-client.js.map +1 -0
  76. package/dist/client/plugins-client.d.ts +17 -0
  77. package/dist/client/plugins-client.d.ts.map +1 -0
  78. package/dist/client/plugins-client.js +9 -0
  79. package/dist/client/plugins-client.js.map +1 -0
  80. package/dist/client/policy-client.d.ts +37 -0
  81. package/dist/client/policy-client.d.ts.map +1 -0
  82. package/dist/client/policy-client.js +26 -0
  83. package/dist/client/policy-client.js.map +1 -0
  84. package/dist/client/presets-client.d.ts +334 -0
  85. package/dist/client/presets-client.d.ts.map +1 -0
  86. package/dist/client/presets-client.js +38 -0
  87. package/dist/client/presets-client.js.map +1 -0
  88. package/dist/client/profiles-client.d.ts +101 -0
  89. package/dist/client/profiles-client.d.ts.map +1 -0
  90. package/dist/client/profiles-client.js +37 -0
  91. package/dist/client/profiles-client.js.map +1 -0
  92. package/dist/client/schedules-client.d.ts +27 -0
  93. package/dist/client/schedules-client.d.ts.map +1 -0
  94. package/dist/client/schedules-client.js +13 -0
  95. package/dist/client/schedules-client.js.map +1 -0
  96. package/dist/client/settings-schema-client.d.ts +23 -0
  97. package/dist/client/settings-schema-client.d.ts.map +1 -0
  98. package/dist/client/settings-schema-client.js +9 -0
  99. package/dist/client/settings-schema-client.js.map +1 -0
  100. package/dist/client/states-client.d.ts +470 -0
  101. package/dist/client/states-client.d.ts.map +1 -0
  102. package/dist/client/states-client.js +144 -0
  103. package/dist/client/states-client.js.map +1 -0
  104. package/dist/client/storage-client.d.ts +40 -0
  105. package/dist/client/storage-client.d.ts.map +1 -0
  106. package/dist/client/storage-client.js +43 -0
  107. package/dist/client/storage-client.js.map +1 -0
  108. package/dist/client/sub-mcp-client.d.ts +17 -0
  109. package/dist/client/sub-mcp-client.d.ts.map +1 -0
  110. package/dist/client/sub-mcp-client.js +14 -0
  111. package/dist/client/sub-mcp-client.js.map +1 -0
  112. package/dist/client/system-client.d.ts +11 -0
  113. package/dist/client/system-client.d.ts.map +1 -0
  114. package/dist/client/system-client.js +13 -0
  115. package/dist/client/system-client.js.map +1 -0
  116. package/dist/client/templates-client.d.ts +29 -0
  117. package/dist/client/templates-client.d.ts.map +1 -0
  118. package/dist/client/templates-client.js +21 -0
  119. package/dist/client/templates-client.js.map +1 -0
  120. package/dist/client/tool-extensions-client.d.ts +53 -0
  121. package/dist/client/tool-extensions-client.d.ts.map +1 -0
  122. package/dist/client/tool-extensions-client.js +21 -0
  123. package/dist/client/tool-extensions-client.js.map +1 -0
  124. package/dist/client/tool-meta-client.d.ts +69 -0
  125. package/dist/client/tool-meta-client.d.ts.map +1 -0
  126. package/dist/client/tool-meta-client.js +38 -0
  127. package/dist/client/tool-meta-client.js.map +1 -0
  128. package/dist/client/tools-client.d.ts +83 -0
  129. package/dist/client/tools-client.d.ts.map +1 -0
  130. package/dist/client/tools-client.js +38 -0
  131. package/dist/client/tools-client.js.map +1 -0
  132. package/dist/client/transport.d.ts +13 -0
  133. package/dist/client/transport.d.ts.map +1 -0
  134. package/dist/client/transport.js +10 -0
  135. package/dist/client/transport.js.map +1 -0
  136. package/dist/client/trigger-links-client.d.ts +44 -0
  137. package/dist/client/trigger-links-client.d.ts.map +1 -0
  138. package/dist/client/trigger-links-client.js +30 -0
  139. package/dist/client/trigger-links-client.js.map +1 -0
  140. package/dist/client/web-entry-gate-client.d.ts +34 -0
  141. package/dist/client/web-entry-gate-client.d.ts.map +1 -0
  142. package/dist/client/web-entry-gate-client.js +25 -0
  143. package/dist/client/web-entry-gate-client.js.map +1 -0
  144. package/dist/errors.d.ts +11 -0
  145. package/dist/errors.d.ts.map +1 -1
  146. package/dist/errors.js +15 -0
  147. package/dist/errors.js.map +1 -1
  148. package/dist/http.d.ts.map +1 -1
  149. package/dist/http.js +33 -17
  150. package/dist/http.js.map +1 -1
  151. package/dist/index.d.ts +12 -12
  152. package/dist/index.d.ts.map +1 -1
  153. package/dist/index.js +6 -13
  154. package/dist/index.js.map +1 -1
  155. package/dist/schemas/api-keys.d.ts +43 -0
  156. package/dist/schemas/api-keys.d.ts.map +1 -0
  157. package/dist/schemas/api-keys.js +29 -0
  158. package/dist/schemas/api-keys.js.map +1 -0
  159. package/dist/schemas/auth-routes.d.ts +78 -0
  160. package/dist/schemas/auth-routes.d.ts.map +1 -0
  161. package/dist/schemas/auth-routes.js +42 -0
  162. package/dist/schemas/auth-routes.js.map +1 -0
  163. package/dist/schemas/backup.d.ts +78 -0
  164. package/dist/schemas/backup.d.ts.map +1 -0
  165. package/dist/schemas/backup.js +33 -0
  166. package/dist/schemas/backup.js.map +1 -0
  167. package/dist/schemas/capabilities.d.ts +109 -0
  168. package/dist/schemas/capabilities.d.ts.map +1 -0
  169. package/dist/schemas/capabilities.js +78 -0
  170. package/dist/schemas/capabilities.js.map +1 -0
  171. package/dist/schemas/channels.d.ts +7 -0
  172. package/dist/schemas/channels.d.ts.map +1 -0
  173. package/dist/schemas/channels.js +9 -0
  174. package/dist/schemas/channels.js.map +1 -0
  175. package/dist/schemas/config.d.ts +17 -0
  176. package/dist/schemas/config.d.ts.map +1 -0
  177. package/dist/schemas/config.js +17 -0
  178. package/dist/schemas/config.js.map +1 -0
  179. package/dist/schemas/connectors.d.ts +383 -0
  180. package/dist/schemas/connectors.d.ts.map +1 -0
  181. package/dist/schemas/connectors.js +122 -0
  182. package/dist/schemas/connectors.js.map +1 -0
  183. package/dist/schemas/conversations.d.ts +600 -0
  184. package/dist/schemas/conversations.d.ts.map +1 -0
  185. package/dist/schemas/conversations.js +208 -0
  186. package/dist/schemas/conversations.js.map +1 -0
  187. package/dist/schemas/extensions.d.ts +44 -0
  188. package/dist/schemas/extensions.d.ts.map +1 -0
  189. package/dist/schemas/extensions.js +29 -0
  190. package/dist/schemas/extensions.js.map +1 -0
  191. package/dist/schemas/fleet.d.ts +271 -0
  192. package/dist/schemas/fleet.d.ts.map +1 -0
  193. package/dist/schemas/fleet.js +132 -0
  194. package/dist/schemas/fleet.js.map +1 -0
  195. package/dist/schemas/hooks.d.ts +120 -0
  196. package/dist/schemas/hooks.d.ts.map +1 -0
  197. package/dist/schemas/hooks.js +44 -0
  198. package/dist/schemas/hooks.js.map +1 -0
  199. package/dist/schemas/index.d.ts +40 -0
  200. package/dist/schemas/index.d.ts.map +1 -0
  201. package/dist/schemas/index.js +40 -0
  202. package/dist/schemas/index.js.map +1 -0
  203. package/dist/schemas/interactions.d.ts +156 -0
  204. package/dist/schemas/interactions.d.ts.map +1 -0
  205. package/dist/schemas/interactions.js +124 -0
  206. package/dist/schemas/interactions.js.map +1 -0
  207. package/dist/schemas/login.d.ts +93 -0
  208. package/dist/schemas/login.d.ts.map +1 -0
  209. package/dist/schemas/login.js +61 -0
  210. package/dist/schemas/login.js.map +1 -0
  211. package/dist/schemas/manifest-mcp.d.ts +125 -0
  212. package/dist/schemas/manifest-mcp.d.ts.map +1 -0
  213. package/dist/schemas/manifest-mcp.js +61 -0
  214. package/dist/schemas/manifest-mcp.js.map +1 -0
  215. package/dist/schemas/marketplace.d.ts +708 -0
  216. package/dist/schemas/marketplace.d.ts.map +1 -0
  217. package/dist/schemas/marketplace.js +387 -0
  218. package/dist/schemas/marketplace.js.map +1 -0
  219. package/dist/schemas/notifications.d.ts +61 -0
  220. package/dist/schemas/notifications.d.ts.map +1 -0
  221. package/dist/schemas/notifications.js +38 -0
  222. package/dist/schemas/notifications.js.map +1 -0
  223. package/dist/schemas/observability.d.ts +114 -0
  224. package/dist/schemas/observability.d.ts.map +1 -0
  225. package/dist/schemas/observability.js +74 -0
  226. package/dist/schemas/observability.js.map +1 -0
  227. package/dist/schemas/policy.d.ts +58 -0
  228. package/dist/schemas/policy.d.ts.map +1 -0
  229. package/dist/schemas/policy.js +32 -0
  230. package/dist/schemas/policy.js.map +1 -0
  231. package/dist/schemas/presets.d.ts +258 -0
  232. package/dist/schemas/presets.d.ts.map +1 -0
  233. package/dist/schemas/presets.js +95 -0
  234. package/dist/schemas/presets.js.map +1 -0
  235. package/dist/schemas/principals.d.ts +54 -0
  236. package/dist/schemas/principals.d.ts.map +1 -0
  237. package/dist/schemas/principals.js +34 -0
  238. package/dist/schemas/principals.js.map +1 -0
  239. package/dist/schemas/profiles.d.ts +180 -0
  240. package/dist/schemas/profiles.d.ts.map +1 -0
  241. package/dist/schemas/profiles.js +100 -0
  242. package/dist/schemas/profiles.js.map +1 -0
  243. package/dist/schemas/roles.d.ts +125 -0
  244. package/dist/schemas/roles.d.ts.map +1 -0
  245. package/dist/schemas/roles.js +46 -0
  246. package/dist/schemas/roles.js.map +1 -0
  247. package/dist/schemas/schedules.d.ts +25 -0
  248. package/dist/schemas/schedules.d.ts.map +1 -0
  249. package/dist/schemas/schedules.js +24 -0
  250. package/dist/schemas/schedules.js.map +1 -0
  251. package/dist/schemas/served.d.ts +626 -0
  252. package/dist/schemas/served.d.ts.map +1 -0
  253. package/dist/schemas/served.js +28 -0
  254. package/dist/schemas/served.js.map +1 -0
  255. package/dist/schemas/settings-schema.d.ts +23 -0
  256. package/dist/schemas/settings-schema.d.ts.map +1 -0
  257. package/dist/schemas/settings-schema.js +25 -0
  258. package/dist/schemas/settings-schema.js.map +1 -0
  259. package/dist/schemas/setup.d.ts +43 -0
  260. package/dist/schemas/setup.d.ts.map +1 -0
  261. package/dist/schemas/setup.js +19 -0
  262. package/dist/schemas/setup.js.map +1 -0
  263. package/dist/schemas/shared.d.ts +20 -0
  264. package/dist/schemas/shared.d.ts.map +1 -0
  265. package/dist/schemas/shared.js +20 -0
  266. package/dist/schemas/shared.js.map +1 -0
  267. package/dist/schemas/states.d.ts +499 -0
  268. package/dist/schemas/states.d.ts.map +1 -0
  269. package/dist/schemas/states.js +220 -0
  270. package/dist/schemas/states.js.map +1 -0
  271. package/dist/schemas/storage.d.ts +37 -0
  272. package/dist/schemas/storage.d.ts.map +1 -0
  273. package/dist/schemas/storage.js +24 -0
  274. package/dist/schemas/storage.js.map +1 -0
  275. package/dist/schemas/studio-plugins.d.ts +30 -0
  276. package/dist/schemas/studio-plugins.d.ts.map +1 -0
  277. package/dist/schemas/studio-plugins.js +20 -0
  278. package/dist/schemas/studio-plugins.js.map +1 -0
  279. package/dist/schemas/sub-mcp.d.ts +29 -0
  280. package/dist/schemas/sub-mcp.d.ts.map +1 -0
  281. package/dist/schemas/sub-mcp.js +22 -0
  282. package/dist/schemas/sub-mcp.js.map +1 -0
  283. package/dist/schemas/system-kinds.d.ts +122 -0
  284. package/dist/schemas/system-kinds.d.ts.map +1 -0
  285. package/dist/schemas/system-kinds.js +40 -0
  286. package/dist/schemas/system-kinds.js.map +1 -0
  287. package/dist/schemas/templates.d.ts +26 -0
  288. package/dist/schemas/templates.d.ts.map +1 -0
  289. package/dist/schemas/templates.js +11 -0
  290. package/dist/schemas/templates.js.map +1 -0
  291. package/dist/schemas/tool-meta.d.ts +64 -0
  292. package/dist/schemas/tool-meta.d.ts.map +1 -0
  293. package/dist/schemas/tool-meta.js +44 -0
  294. package/dist/schemas/tool-meta.js.map +1 -0
  295. package/dist/schemas/tools.d.ts +62 -0
  296. package/dist/schemas/tools.d.ts.map +1 -0
  297. package/dist/schemas/tools.js +53 -0
  298. package/dist/schemas/tools.js.map +1 -0
  299. package/dist/schemas/trigger-links.d.ts +71 -0
  300. package/dist/schemas/trigger-links.d.ts.map +1 -0
  301. package/dist/schemas/trigger-links.js +46 -0
  302. package/dist/schemas/trigger-links.js.map +1 -0
  303. package/dist/schemas/web-entry.d.ts +45 -0
  304. package/dist/schemas/web-entry.d.ts.map +1 -0
  305. package/dist/schemas/web-entry.js +36 -0
  306. package/dist/schemas/web-entry.js.map +1 -0
  307. package/dist/tool-runs.d.ts.map +1 -1
  308. package/dist/tool-runs.js.map +1 -1
  309. package/package.json +1 -1
  310. package/src/agents.ts +2 -2
  311. package/src/client/agents-client.ts +23 -0
  312. package/src/client/auth-client.ts +170 -0
  313. package/src/client/backend-client.ts +25 -0
  314. package/src/client/backup-client.ts +16 -0
  315. package/src/client/capabilities-client.ts +22 -0
  316. package/src/client/channels-client.ts +11 -0
  317. package/src/client/config-client.ts +21 -0
  318. package/src/client/connectors-client.ts +52 -0
  319. package/src/client/conversations-client.ts +240 -0
  320. package/src/client/hooks-client.ts +44 -0
  321. package/src/client/index.ts +122 -0
  322. package/src/client/interactions-client.ts +89 -0
  323. package/src/client/login-client.ts +150 -0
  324. package/src/client/manifest-client.ts +118 -0
  325. package/src/client/marketplace-client.ts +122 -0
  326. package/src/client/mcp-config-schema-client.ts +11 -0
  327. package/src/client/notifications-client.ts +13 -0
  328. package/src/client/observability-client.ts +82 -0
  329. package/src/client/plugins-client.ts +11 -0
  330. package/src/client/policy-client.ts +41 -0
  331. package/src/client/presets-client.ts +124 -0
  332. package/src/client/profiles-client.ts +51 -0
  333. package/src/client/schedules-client.ts +22 -0
  334. package/src/client/settings-schema-client.ts +11 -0
  335. package/src/client/states-client.ts +292 -0
  336. package/src/client/storage-client.ts +63 -0
  337. package/src/client/sub-mcp-client.ts +17 -0
  338. package/src/client/system-client.ts +16 -0
  339. package/src/client/templates-client.ts +28 -0
  340. package/src/client/tool-extensions-client.ts +24 -0
  341. package/src/client/tool-meta-client.ts +65 -0
  342. package/src/client/tools-client.ts +66 -0
  343. package/src/client/transport.ts +18 -0
  344. package/src/client/trigger-links-client.ts +51 -0
  345. package/src/client/web-entry-gate-client.ts +45 -0
  346. package/src/errors.ts +16 -0
  347. package/src/http.ts +48 -24
  348. package/src/index.ts +231 -226
  349. package/src/schemas/api-keys.ts +34 -0
  350. package/src/schemas/auth-routes.ts +48 -0
  351. package/src/schemas/backup.ts +43 -0
  352. package/src/schemas/capabilities.ts +92 -0
  353. package/src/schemas/channels.ts +11 -0
  354. package/src/schemas/config.ts +17 -0
  355. package/src/schemas/connectors.ts +139 -0
  356. package/src/schemas/conversations.ts +257 -0
  357. package/src/schemas/extensions.ts +34 -0
  358. package/src/schemas/fleet.ts +154 -0
  359. package/src/schemas/hooks.ts +57 -0
  360. package/src/schemas/index.ts +39 -0
  361. package/src/schemas/interactions.ts +147 -0
  362. package/src/schemas/login.ts +69 -0
  363. package/src/schemas/manifest-mcp.ts +70 -0
  364. package/src/schemas/marketplace.ts +447 -0
  365. package/src/schemas/notifications.ts +43 -0
  366. package/src/schemas/observability.ts +87 -0
  367. package/src/schemas/policy.ts +38 -0
  368. package/src/schemas/presets.ts +114 -0
  369. package/src/schemas/principals.ts +41 -0
  370. package/src/schemas/profiles.ts +120 -0
  371. package/src/schemas/roles.ts +58 -0
  372. package/src/schemas/schedules.ts +28 -0
  373. package/src/schemas/served.ts +50 -0
  374. package/src/schemas/settings-schema.ts +32 -0
  375. package/src/schemas/setup.ts +39 -0
  376. package/src/schemas/shared.ts +21 -0
  377. package/src/schemas/states.ts +273 -0
  378. package/src/schemas/storage.ts +31 -0
  379. package/src/schemas/studio-plugins.ts +21 -0
  380. package/src/schemas/sub-mcp.ts +24 -0
  381. package/src/schemas/system-kinds.ts +47 -0
  382. package/src/schemas/templates.ts +12 -0
  383. package/src/schemas/tool-meta.ts +51 -0
  384. package/src/schemas/tools.ts +62 -0
  385. package/src/schemas/trigger-links.ts +55 -0
  386. package/src/schemas/web-entry.ts +46 -0
  387. package/src/tool-runs.ts +1 -1
  388. package/dist/client.d.ts.map +0 -1
  389. package/dist/client.js +0 -920
  390. package/dist/client.js.map +0 -1
  391. package/dist/schemas.d.ts +0 -5172
  392. package/dist/schemas.d.ts.map +0 -1
  393. package/dist/schemas.js +0 -2268
  394. package/dist/schemas.js.map +0 -1
  395. package/src/client.ts +0 -1771
  396. package/src/schemas.ts +0 -2760
package/dist/schemas.js DELETED
@@ -1,2268 +0,0 @@
1
- /**
2
- * One zod schema per consumed endpoint. These mirror the skeleton's router
3
- * response shapes exactly; a drift throws (ApiSchemaError) and the UI shows the
4
- * error state. JSON-schema-shaped fields are kept as permissive records — the
5
- * auto-form renderer interprets them at runtime.
6
- */
7
- import { z } from 'zod';
8
- import { templatedText } from './templated-text';
9
- import * as generated from './generated/served-schemas';
10
- export { templatedText, requiredTemplatedText } from './templated-text';
11
- // Served-document schemas are GENERATED from the platform contract JSON-schema
12
- // bundle (src/generated/served-schemas.ts) and re-exported here under the names the
13
- // rest of the client uses. The generator maps every `x-tai42-templated-text` field
14
- // to the shared `templatedText` zod, so a served body can never be a bare string.
15
- // The plain response DTOs below (list wrappers, acks, version rows) stay hand-written.
16
- export const stateInjection = generated.stateInjection;
17
- export const stateUpdate = generated.stateUpdate;
18
- export const stateAttach = generated.stateAttach;
19
- export const stateBinding = generated.stateBinding;
20
- export const presetBody = generated.presetBody;
21
- export const conversationRoute = generated.conversationRoute;
22
- export const conversationRouteCreate = generated.conversationRouteCreate;
23
- export const targetConversationConfig = generated.targetConversationConfig;
24
- export const channelTemplate = generated.channelTemplate;
25
- export const hookSubject = generated.hookSubject;
26
- export const hookParams = generated.hookParams;
27
- export const hookRegister = generated.hookRegister;
28
- export const stateDeclaration = generated.stateDeclaration;
29
- export const stateTemplateDocument = generated.stateTemplateDocument;
30
- export const templateJq = generated.stateTemplateJq;
31
- export const templateReconcile = generated.stateTemplateReconcile;
32
- export const templateDeclarations = generated.stateTemplateDeclarations;
33
- export const policyBody = generated.accessPolicy;
34
- export const roleBody = generated.roleDefinition;
35
- /** An arbitrary JSON value (tool results, rendered payloads). */
36
- export const jsonValue = z.unknown();
37
- /** A JSON Schema object (Pydantic-emitted). Permissive; parsed by the auto-form. */
38
- export const jsonSchema = z.record(z.string(), z.unknown());
39
- // -- tools -------------------------------------------------------------------
40
- export const toolNames = z.array(z.string());
41
- export const toolSchema = z.object({
42
- input: jsonSchema,
43
- output: jsonSchema.nullable(),
44
- description: z.string().nullable(),
45
- });
46
- export const allToolSchemas = z.record(z.string(), toolSchema);
47
- export const runToolResult = jsonValue;
48
- /**
49
- * The MEDIA content shape a direct tool run may return — fastmcp's serialized
50
- * `Image`/`Audio` MediaBlock (`{ type, data: <base64>, mimeType }`). One recognised
51
- * shape of the otherwise-arbitrary `runToolResult`, kept as its own schema so the
52
- * viewer detects media by parse, not by ad-hoc shape check.
53
- *
54
- * SECURITY: the refinement pins `mimeType` to its kind — `image` MUST be `image/*`,
55
- * `audio` MUST be `audio/*` — so a drifting/arbitrary mime fails the parse and is
56
- * never turned into a `data:` URI (a `File` MediaBlock's distinct `EmbeddedResource`
57
- * shape also fails here, by design).
58
- */
59
- export const toolMediaResult = z
60
- .object({
61
- type: z.enum(['image', 'audio']),
62
- data: z.string(),
63
- mimeType: z.string(),
64
- })
65
- .refine((media) => media.mimeType.startsWith(`${media.type}/`), {
66
- message: 'media mimeType must match its media kind (image/* for image, audio/* for audio)',
67
- path: ['mimeType'],
68
- });
69
- /**
70
- * The ADDITIVE per-tool native surface (`GET /api/tools/tags`). Distinct from the
71
- * flat `toolNames` contract (`GET /api/tools`, unchanged): each entry carries the
72
- * tool's read-only FastMCP `tags` — so the shared `ToolPicker` can group/filter its
73
- * options — plus `hidden`, the tool's OWN plugin-declared visibility (read from the
74
- * FastMCP `meta` under `tai42/hidden`; a tool that never declared it is not hidden).
75
- * The tool_meta overlay's tri-state override is merged on top client-side; this read
76
- * exposes only the declaration.
77
- *
78
- * `badges` are the tool's plugin-DECLARED capability labels — purely INFORMATIONAL
79
- * (e.g. `network`, `filesystem`), never a gate the server enforces. The overlay's
80
- * own badges are merged on top client-side; this read exposes only the declaration.
81
- */
82
- export const toolTagEntry = z.object({
83
- name: z.string(),
84
- tags: z.array(z.string()),
85
- badges: z.array(z.string()),
86
- hidden: z.boolean(),
87
- });
88
- export const toolTags = z.array(toolTagEntry);
89
- // -- extensions --------------------------------------------------------------
90
- export const extension = z.object({ name: z.string(), kind: z.string() });
91
- export const extensions = z.array(extension);
92
- /**
93
- * One element of an extension combo: a bare extension NAME, or a
94
- * `{ name, config }` mapping binding author config (e.g. an `output_schema` JSON
95
- * Schema, or an `ask_external` verifier). Both wire forms are admitted so a
96
- * config-bearing combo parses without dropping server data. A drift throws
97
- * `ApiSchemaError`.
98
- */
99
- export const presetExtensionElement = z.union([
100
- z.string(),
101
- z.object({ name: z.string(), config: z.record(z.string(), z.unknown()) }),
102
- ]);
103
- /**
104
- * `GET /api/tools/{name}/extensions` — a tool's FULL lossless list-of-combos plus
105
- * the extension catalog. `combos` is a list of combos, each an ordered list of
106
- * extension ELEMENTS (a bare name or a config-bearing `{ name, config }` mapping —
107
- * `output_schema` carries its schema this way); `[]` when the tool has no map entry.
108
- * It carries EVERY combo mapped to the base tool (the union across every `tools`/`mcp`
109
- * config), never a single flattened one. `available` is the same flat catalog
110
- * `GET /api/extensions` returns. A drift throws `ApiSchemaError`.
111
- */
112
- export const toolExtensions = z.object({
113
- combos: z.array(z.array(presetExtensionElement)),
114
- available: extensions,
115
- });
116
- // -- presets -----------------------------------------------------------------
117
- /** A list of extension COMBOS — each combo an ordered list of elements. */
118
- export const presetExtensions = z.array(z.array(presetExtensionElement));
119
- /**
120
- * One preset as `GET /api/presets` returns it. Every preset is versioned, so
121
- * `active_version` is always an int; `conflicted` marks a QUARANTINED row (its
122
- * name collided with a foreign tool at boot — delete-only). `extensions` are the
123
- * ACTIVE version's extension combos, `output_schema` the optional author-set
124
- * output JSON Schema, and `input_schema` the optional author-set input JSON
125
- * Schema. Categorization tags live in the tool_meta overlay
126
- * (`GET /api/tool-meta`), never on the record. A drift throws `ApiSchemaError`;
127
- * nothing is coerced.
128
- */
129
- export const presetRecord = z.object({
130
- name: z.string(),
131
- base_tool: z.string(),
132
- description: z.string(),
133
- active_version: z.number(),
134
- extensions: presetExtensions,
135
- output_schema: z.record(z.string(), z.unknown()).nullable(),
136
- input_schema: z.record(z.string(), z.unknown()).nullable(),
137
- conflicted: z.boolean(),
138
- // The human-readable cause a row is quarantined (its name collided with a
139
- // foreign tool at boot), or `null` when the row is not conflicted. Rendered
140
- // verbatim; nothing is coerced.
141
- conflicted_reason: z.string().nullable(),
142
- // Sorted preset-name cross-references: `uses` names the presets this one
143
- // composes as tools; `used_by` names the presets that compose this one.
144
- uses: z.array(z.string()),
145
- used_by: z.array(z.string()),
146
- });
147
- export const presetList = z.array(presetRecord);
148
- /** `GET /api/presets/{name}` — the record plus the active version's baked kwargs. */
149
- export const presetDetail = presetRecord.extend({
150
- fixed_kwargs: z.record(z.string(), z.unknown()),
151
- });
152
- /**
153
- * One immutable version row (`GET /api/presets/{name}/versions[/{version}]`).
154
- * `is_current` flags the active version; `tags` here is the GENERIC per-version
155
- * label list (kind-agnostic) — the only preset tags that remain, distinct from the
156
- * removed record-level categorization and from the tool_meta overlay.
157
- */
158
- export const presetVersion = z.object({
159
- version: z.number(),
160
- body: presetBody,
161
- tags: z.array(z.string()),
162
- created_at: z.string(),
163
- is_current: z.boolean(),
164
- });
165
- export const presetVersionList = z.array(presetVersion);
166
- /** `POST /api/presets/{name}/rollback` — the re-pointed active version. */
167
- export const presetRollback = z.object({ name: z.string(), active_version: z.number() });
168
- /** `DELETE /api/presets/{name}` — the removed preset. */
169
- export const presetDeleted = z.object({ name: z.string(), deleted: z.literal(true) });
170
- /** `POST /api/presets/{name}/rename` — the re-keyed record identity. */
171
- export const presetRenamed = z.object({
172
- name: z.string(),
173
- renamed_from: z.string(),
174
- active_version: z.number(),
175
- });
176
- /**
177
- * `GET /api/presets/{name}/referees` — every OTHER preset whose active authored
178
- * composition names this one as a tool (the referees a rename would strand). An
179
- * empty list is the clean case; a non-empty list means a rename is blocked until
180
- * those presets are updated. A drift throws `ApiSchemaError`.
181
- */
182
- export const presetReferees = z.object({
183
- name: z.string(),
184
- referees: z.array(z.string()),
185
- });
186
- /**
187
- * `POST /api/presets/validate` — the dry-run verdict for a preset draft. `valid`
188
- * is the absence of an `error`; an invalid draft is a SUCCESSFUL validation (HTTP
189
- * 200), so `error` carries the server's verbatim message. A drift throws
190
- * `ApiSchemaError`.
191
- */
192
- export const presetValidation = z.object({
193
- valid: z.boolean(),
194
- error: z.string().nullable(),
195
- });
196
- /**
197
- * `PUT /api/presets/{name}/versions/{version}/tags` — the re-annotated version.
198
- * Version tags are labels on an immutable body, so this rebinds nothing; the
199
- * response echoes the identity plus the new tag list. A drift throws
200
- * `ApiSchemaError`.
201
- */
202
- export const presetVersionTags = z.object({
203
- name: z.string(),
204
- version: z.number(),
205
- tags: z.array(z.string()),
206
- });
207
- // -- tool_meta (the organizational overlay) ----------------------------------
208
- /**
209
- * One folder in the tool-organization tree (`tool_folders`). `parent_id` is `null`
210
- * for a root folder and otherwise the containing folder's `id`; nesting is endless
211
- * via the parent chain. Ids are UUID strings. A drift throws `ApiSchemaError`.
212
- */
213
- export const folderRecord = z.object({
214
- id: z.string(),
215
- name: z.string(),
216
- parent_id: z.string().nullable(),
217
- });
218
- /**
219
- * The organizational overlay for one tool, keyed by `tool_name`. `display_name`
220
- * overrides the rendered label (`display_name ?? name`); `folder_id` places the tool
221
- * in a folder (`null` = unfiled); `tags` is the user's editable categorization,
222
- * merged with the tool's read-only native tags by the UI; `badges` is the operator's
223
- * editable capability-label overlay, merged with the tool's read-only plugin-declared
224
- * badges by the UI (INFORMATIONAL, never an enforced gate); `hidden` is TRI-STATE —
225
- * `null` = defer to the plugin declaration, `true` = force hidden, `false` = force
226
- * visible. A drift throws `ApiSchemaError`.
227
- */
228
- export const toolMetaRecord = z.object({
229
- tool_name: z.string(),
230
- display_name: z.string().nullable(),
231
- folder_id: z.string().nullable(),
232
- tags: z.array(z.string()),
233
- badges: z.array(z.string()),
234
- hidden: z.boolean().nullable(),
235
- });
236
- /**
237
- * `GET /api/tool-meta` — the whole overlay in one read: the flat folder tree plus
238
- * every per-tool row. The UI builds the tree and merges the rows against the live
239
- * tool list client-side. A drift throws `ApiSchemaError`.
240
- */
241
- export const toolMetaOverlay = z.object({
242
- folders: z.array(folderRecord),
243
- meta: z.array(toolMetaRecord),
244
- });
245
- /** `DELETE /api/tool-meta/tools/{tool_name}` — the dropped overlay row (idempotent). */
246
- export const toolMetaDeleted = z.object({ tool_name: z.string(), deleted: z.literal(true) });
247
- /** `DELETE /api/tool-meta/folders/{folder_id}` — the removed empty folder. */
248
- export const folderDeleted = z.object({ folder_id: z.string(), deleted: z.literal(true) });
249
- // -- templates ---------------------------------------------------------------
250
- export const templateNames = z.array(z.string());
251
- export const templateDetail = z.object({ template: z.string(), schema: jsonSchema });
252
- export const templateUploaded = z.object({ path: z.string(), uploaded: z.literal(true) });
253
- export const templateDeleted = z.object({ path: z.string(), deleted: z.literal(true) });
254
- export const templateDirDeleted = z.object({ path: z.string(), deleted: z.literal(true) });
255
- export const templateRendered = z.object({ rendered: z.string() });
256
- export const templateCacheCleared = z.object({ cleared: z.literal(true) });
257
- // -- storage -----------------------------------------------------------------
258
- /** `GET /api/storage` — the storage-provider identity, or the absent sentinel
259
- * (`present: false`, a 200) when no storage-provider plugin is installed. */
260
- export const storageInfo = z.object({
261
- present: z.boolean(),
262
- provider: z.string().nullable(),
263
- module: z.string().nullable(),
264
- });
265
- /** `GET /api/storage/resources` — the full sorted resource-id list. */
266
- export const storageResourceList = z.object({ resources: z.array(z.string()) });
267
- /** `GET /api/storage/resources/{id}/stat` — an object's inferred content type;
268
- * `null` when the provider cannot infer one (e.g. an unknown suffix). */
269
- export const storageResourceStat = z.object({
270
- id: z.string(),
271
- content_type: z.string().nullable(),
272
- });
273
- /** `POST /api/storage/resources` — the stored object's id. */
274
- export const storageResourceStored = z.object({ id: z.string(), stored: z.literal(true) });
275
- /** `DELETE /api/storage/resources/{id}` — the removed object's id. */
276
- export const storageResourceDeleted = z.object({ id: z.string(), deleted: z.literal(true) });
277
- /** `DELETE /api/storage/dirs/{path}` — the removed directory subtree. */
278
- export const storageDirDeleted = z.object({ dir: z.string(), deleted: z.literal(true) });
279
- // -- backend identity + fleet (worker bus) -----------------------------------
280
- /** `GET /api/backend` — the execution-backend identity, or the absent sentinel
281
- * (`present: false`, a 200) when no backend plugin is registered. Backend identity
282
- * is kept distinct from the fleet: the fleet doors ride the app's worker bus and
283
- * need no backend at all. */
284
- export const backendInfo = z.object({
285
- present: z.boolean(),
286
- backend: z.string().nullable(),
287
- module: z.string().nullable(),
288
- });
289
- /** The two worker kinds that join the bus: an ASGI `serve` worker or a
290
- * `backend` runtime process. A drift throws `ApiSchemaError`. */
291
- export const workerKind = z.enum(['serve', 'backend']);
292
- /** The lifecycle state a worker advertises in its presence value: `ready` once its
293
- * resync has converged, `resyncing` while a boot/reconnect resync runs, `recycling`
294
- * once it has begun a graceful self-exit. A drift throws `ApiSchemaError`. */
295
- export const workerState = z.enum(['ready', 'resyncing', 'recycling']);
296
- /** The last op a worker applied, stamped onto its presence row after the terminal
297
- * reply. `outcome` is the free op-outcome string; `at` is the ISO instant it landed. */
298
- export const workerLastOp = z.object({
299
- op: z.string(),
300
- outcome: z.string(),
301
- at: z.string(),
302
- });
303
- /**
304
- * One live worker on the bus — a presence-census row. `name` is the stable slot
305
- * (`{kind}-{n}`) that doubles as a reload target; `generation` is the monotonic life
306
- * counter minted with the worker's claim; `kind` tells the two worker kinds apart;
307
- * `pid` is the process id. `joined_at`/`beat_at` are ISO instants (first-seen and last
308
- * heartbeat) for the cosmetic seen-since display; `state` is the advertised lifecycle
309
- * state; `stale` is SERVER-computed from the row's remaining presence TTL against the
310
- * bus cadence (a quiet row past the freshness bound — reconnecting or dead) and is the
311
- * only freshness signal a client reads, never a client-side threshold; `last_op` is the
312
- * worker's last applied op, or `null` before it has applied one.
313
- */
314
- export const fleetWorker = z.object({
315
- name: z.string(),
316
- kind: workerKind,
317
- pid: z.number(),
318
- generation: z.number(),
319
- joined_at: z.string(),
320
- beat_at: z.string(),
321
- state: workerState,
322
- stale: z.boolean(),
323
- last_op: workerLastOp.nullable(),
324
- });
325
- /**
326
- * `GET /api/fleet/workers` — the live worker fleet from the bus presence census.
327
- * The census lists ALL subscribed workers (ASGI `serve` workers and backend-runtime
328
- * processes alike), not only backend workers. A census read that fails surfaces as a
329
- * loud 500, never a fabricated empty fleet.
330
- */
331
- export const fleetWorkers = z.object({ workers: z.array(fleetWorker) });
332
- /**
333
- * One worker's outcome within a fleet broadcast. `applied`/`failed` are terminal wire
334
- * replies from a subscriber; `missing`/`departed`/`timed_out` are publisher-computed
335
- * from the presence census (a silent worker never sends them); `resyncing`/`recycling`/
336
- * `stale` are the gap outcomes for a row that failed the ready+fresh gate — reported as
337
- * its own actual condition rather than dropped (`resyncing` converges on its resync,
338
- * `recycling` is departing, `stale` is a quiet row past the freshness bound carrying no
339
- * convergence promise).
340
- */
341
- export const fleetOutcome = z.enum([
342
- 'applied',
343
- 'failed',
344
- 'missing',
345
- 'departed',
346
- 'timed_out',
347
- 'resyncing',
348
- 'recycling',
349
- 'stale',
350
- ]);
351
- /**
352
- * One worker's result within a {@link fleetResult}. `payload` carries query-op data
353
- * (opaque to the UI); `error` carries a failed apply's message; `detail` carries the
354
- * publisher's report text for a computed gap outcome (`missing`/`departed`/`timed_out`/
355
- * `resyncing`/`recycling`/`stale`). A drift throws `ApiSchemaError`.
356
- */
357
- export const fleetWorkerResult = z.object({
358
- name: z.string(),
359
- outcome: fleetOutcome,
360
- payload: jsonValue,
361
- error: z.string().nullable(),
362
- detail: z.string().nullable(),
363
- });
364
- /**
365
- * The awaited per-worker report of one fleet broadcast. Two honest shapes ride the
366
- * same schema. Reachable (`reachable: true`): `results` holds one entry per expected
367
- * worker (the serving worker's own entry included) plus the gap rows, so an unconfirmed
368
- * sibling is a visible `failed`/`missing`/`departed`/`timed_out`/`resyncing`/`recycling`/
369
- * `stale` entry, never a silent stale worker. Bus-unreachable (`reachable: false`): the
370
- * transport failed before any worker could reply, so `results` is empty and only `error`
371
- * is carried. This is the bare body of `POST /api/fleet/reload-config` and the single-MCP
372
- * reload; it is also the body the mode-wrapped {@link fleetReportFanout} carries under its
373
- * `fleet` / `unreachable` modes.
374
- */
375
- export const fleetResult = z.object({
376
- op: z.string(),
377
- reachable: z.boolean(),
378
- local_only: z.boolean(),
379
- results: z.array(fleetWorkerResult),
380
- error: z.string().nullable(),
381
- });
382
- /**
383
- * `POST /api/fleet/reload-config` — soft-restart the fleet and report per-worker. The
384
- * serving worker applies its own reload first, then broadcasts; the returned report
385
- * names every worker's outcome. A failed local apply does not abort the broadcast, so
386
- * the report is embedded even on the convergence-failure path.
387
- */
388
- export const fleetReloadResult = fleetResult;
389
- /**
390
- * The mode-wrapped fan-out summary a mutation embeds under its `fanout` field. Three
391
- * honest modes, discriminated on `mode`:
392
- * - `local-only` — the broadcast reached no sibling (a lone worker / no bus), a
393
- * benign single-process note.
394
- * - `fleet` — a reachable multi-worker broadcast; carries the full {@link
395
- * fleetResult} so an unconfirmed sibling is visible.
396
- * - `unreachable` — the bus itself could not be reached; carries the
397
- * bus-unreachable {@link fleetResult} (no worker list, only `error`).
398
- *
399
- * Every mutation whose response embeds this parses it EXPLICITLY: zod's default
400
- * unknown-key stripping would otherwise silently drop the field, hiding a failed
401
- * propagation from the shared fleet-report handler. A drift throws `ApiSchemaError`.
402
- */
403
- export const fleetReportFanout = z.discriminatedUnion('mode', [
404
- z.object({ mode: z.literal('local-only'), note: z.string() }),
405
- fleetResult.extend({ mode: z.literal('fleet') }),
406
- fleetResult.extend({ mode: z.literal('unreachable') }),
407
- ]);
408
- // -- manifest / mcp ----------------------------------------------------------
409
- /**
410
- * The back-reference a connector writes onto a manifest MCP entry to mark it
411
- * connector-owned: the connection and the provider sub-service that own it.
412
- * Hand-authored entries carry no `managed` marker.
413
- */
414
- export const connectorRef = z.object({
415
- connection_id: z.string(),
416
- provider_id: z.string(),
417
- sub_service: z.string(),
418
- });
419
- /**
420
- * One entry of the live manifest's MCP section. Only the `managed` provenance
421
- * marker is typed — the connect/disconnect flows write it server-side to point a
422
- * connector-owned entry back at its connection, and the editor renders such
423
- * entries read-only. `.nullish()` because a hand-authored entry carries `null`
424
- * (present) or omits the key. Every other field (title, config, extensions) rides
425
- * through `.loose()` unmodeled so the config editor keeps editing the whole
426
- * entry — narrowing it to a typed subset would silently strip the fields it saves.
427
- */
428
- export const manifestMcpEntry = z
429
- .object({
430
- managed: connectorRef.nullish(),
431
- })
432
- .loose();
433
- export const manifestView = z.object({
434
- mcp: z.array(manifestMcpEntry),
435
- user_tools: z.array(z.string()),
436
- });
437
- /**
438
- * One `!ENV ${VAR[:default]}` marker the manifest's MCP section carries
439
- * (`GET /api/manifest/mcp-env-refs`) — NAMES and BOOLEANS only, NEVER values.
440
- * `pointer` is the RFC 6901 json-pointer of the leaf (`/mcp/<i>/config/...`);
441
- * `has_default` is whether the marker carries a `:default`; `set` is whether the
442
- * var resolves in the EFFECTIVE env (the resolution truth the install-time
443
- * dangling refusal reads), so a var supplied by the deployment shows green, never
444
- * a false red. The checklist derives from THIS alone — no env value is ever fetched.
445
- */
446
- export const mcpEnvRef = z.object({
447
- var: z.string(),
448
- pointer: z.string(),
449
- has_default: z.boolean(),
450
- set: z.boolean(),
451
- });
452
- export const mcpEnvRefs = z.array(mcpEnvRef);
453
- /**
454
- * The apply result every config-writer mutation returns (`POST /api/mcp-config`,
455
- * `POST /api/config/env`): the serving worker's local reload result (`status` +
456
- * `env_keys`) plus the mode-wrapped fleet fan-out of the reload it broadcast. The
457
- * `fanout` is parsed EXPLICITLY so the shared fleet-report handler can surface a
458
- * failed propagation — zod's unknown-key stripping would otherwise hide it. A drift
459
- * throws `ApiSchemaError`.
460
- */
461
- export const reloadConfigResult = z.object({
462
- status: z.string(),
463
- env_keys: z.number(),
464
- fanout: fleetReportFanout,
465
- });
466
- // -- system kinds ------------------------------------------------------------
467
- // `GET /api/system/kinds` — one row per pluggable kind (identity, accounts,
468
- // monitoring, storage, backend, channels, webhook_verifiers, config,
469
- // studio_plugins). `state` is the kind's active/default/off status: `active` = a
470
- // real plugin serves it, `default` = a built-in fallback serves it, `off` =
471
- // nothing is registered (a legal state, reported not "fixed"). `plugin` is the
472
- // provider/module name when known, else null. Plain (non-strict) `z.object` so a
473
- // server that adds a field to the row still parses.
474
- export const kindStatus = z.object({
475
- kind: z.string(),
476
- state: z.enum(['active', 'default', 'off']),
477
- plugin: z.string().nullable(),
478
- detail: z.string(),
479
- });
480
- export const kindStatusList = z.array(kindStatus);
481
- /**
482
- * `POST /api/tools/{name}/extensions` — the apply result. The write persists the
483
- * manifest, reloads locally, then broadcasts the reload to the whole fleet. The
484
- * response is the one apply-result shape every config-writer returns: the local
485
- * reload result (`status` + `env_keys`) plus the mode-wrapped fleet `fanout`. The
486
- * fan-out rides EVERY deployment (a lone worker reports `local-only`), so this flat
487
- * shape parses every save and the shared fleet-report handler renders any failed
488
- * propagation from `fanout`.
489
- */
490
- export const toolExtensionsApplyResult = reloadConfigResult;
491
- export const mcpStatus = z.object({
492
- bound: z.record(z.string(), z.array(z.string())),
493
- failed: z.array(z.object({ title: z.string(), status: z.string() })),
494
- });
495
- /**
496
- * `POST /api/mcp-status/{title}/reload` — re-probe a single MCP server and broadcast
497
- * the reload to the fleet. The response is the bare per-worker {@link fleetResult}
498
- * (the serving worker's re-probe rides its own `results` entry as the payload); there
499
- * is no local/workers split. A drift throws `ApiSchemaError`.
500
- */
501
- export const mcpReloadResult = fleetResult;
502
- // -- sub-mcp -----------------------------------------------------------------
503
- /**
504
- * One registered sub-MCP mount as it rides the registry list and the projection:
505
- * the tools it exposes and the transport it serves on. In `GET /api/sub-mcp` the
506
- * slug is the map key, so the mount value carries no slug; {@link subMcpEntry}
507
- * extends this with `slug` for the capability projection where mounts are a flat
508
- * list. `transport` is always present on the wire (the server defaults it to
509
- * `http`), so it is required — its absence is a drift, not a legal shape.
510
- */
511
- export const subMcpMount = z.object({
512
- tools: z.array(z.string()),
513
- transport: z.string(),
514
- });
515
- export const subMcpList = z.record(z.string(), subMcpMount);
516
- export const subMcpCreated = z.object({
517
- slug: z.string(),
518
- tools: z.array(z.string()),
519
- transport: z.string(),
520
- });
521
- export const subMcpRemoved = z.object({ slug: z.string(), removed: z.literal(true) });
522
- // -- config ------------------------------------------------------------------
523
- export const envConfig = z.object({
524
- env: z.record(z.string(), z.string()),
525
- secret_keys: z.array(z.string()),
526
- });
527
- /**
528
- * `GET /api/config/mode` — the active config backend mode (`file` / `k8s`). The
529
- * skeleton emits only `config_mode`; `read_only` is a UI-side gate, tolerated-absent
530
- * and defaulting to `false` (writable) so a normal response never drifts, while a
531
- * genuinely read-only deployment can opt in by emitting `read_only: true`.
532
- */
533
- export const configMode = z.object({
534
- config_mode: z.string(),
535
- read_only: z.boolean().default(false),
536
- });
537
- // -- settings profiles -------------------------------------------------------
538
- // The admin-only `/api/config/profiles/*` surface. Secrets ride the wire in the
539
- // clear (secret/fenced routes); masking is CLIENT-SIDE per the secret-mask union. A drift
540
- // on any of these throws `ApiSchemaError`.
541
- /**
542
- * `GET /api/config/profiles` — one row per stored profile. The list is
543
- * names+descriptions ONLY (action=read); no `env`, no `secret_keys`, no bodies.
544
- * (No `last_modified`: the list carries identity, not history — version metadata
545
- * is the `/versions` surface — so the list renders no last-modified column.)
546
- */
547
- export const settingsProfileSummary = z.object({
548
- name: z.string(),
549
- description: z.string(),
550
- });
551
- export const settingsProfileList = z.array(settingsProfileSummary);
552
- /**
553
- * `GET /api/config/profiles/{name}` and each version body — the stored profile
554
- * document (action=secret). `env` carries REAL values; `secret_keys` is the
555
- * per-profile secret-marks band folded into the secret-mask union for masking.
556
- */
557
- export const settingsProfileBody = z.object({
558
- description: z.string(),
559
- env: z.record(z.string(), z.string()),
560
- secret_keys: z.array(z.string()),
561
- });
562
- /** `PUT /api/config/profiles/{name}` — a minimal save ack; `version` is the new store version. */
563
- export const settingsProfileSaved = z.object({
564
- ok: z.literal(true),
565
- version: z.number().optional(),
566
- });
567
- /** `DELETE /api/config/profiles/{name}` — a minimal removal ack. */
568
- export const settingsProfileDeleted = z.object({ ok: z.literal(true) });
569
- /** `POST /api/config/profiles/{name}/rollback` — the restore ack; `version` is the resulting active version. */
570
- export const settingsProfileRollback = z.object({
571
- ok: z.literal(true),
572
- version: z.number(),
573
- });
574
- /**
575
- * `POST /api/config/profiles/{name}/diff` — the SAVED profile vs the stored env
576
- * (action=secret). `changed` carries real `old`/`new` values (UI masks via
577
- * JsonDiff); `recycle_keys`/`refused_keys` are the diff's recycle-class and
578
- * boundary-refused key names, called out in the UI before apply.
579
- */
580
- export const settingsProfileDiff = z.object({
581
- added: z.array(z.string()),
582
- removed: z.array(z.string()),
583
- changed: z.array(z.object({ key: z.string(), old: z.string(), new: z.string() })),
584
- recycle_keys: z.array(z.string()),
585
- refused_keys: z.array(z.string()),
586
- });
587
- /**
588
- * `POST /api/config/profiles/{name}/apply` — the dedicated `profile_apply_response`
589
- * (action=fenced, destructive). NAMES-ONLY (no env value in any
590
- * section): `hot` is the hot-swapped key names; `recycle` is the orchestrator's
591
- * per-worker section — one `{name, kind, status, generation_before}` row per recycled
592
- * target, `generation_before` the life that was recycled, the applier's OWN row carrying
593
- * the `self-deferred` status literal when the diff has serve-affecting recycle keys;
594
- * `fresh` is the per-kind list of NEW ready lives observed since the pre-apply snapshot
595
- * (each `{name, kind, generation}`), evidence of fresh capacity and never claimed as any
596
- * target's successor; `refused` is `[]` on success by construction (populated
597
- * `{key, reason}` only on a refusal), the populated refusal surfaces being the diff
598
- * preview and the refusal error report. `fanout` is the mode-wrapped fleet broadcast,
599
- * parsed EXPLICITLY so a failed propagation reaches the shared fleet-report handler. A
600
- * drift throws `ApiSchemaError`.
601
- */
602
- export const profileApplyResponse = z.object({
603
- hot: z.array(z.string()),
604
- recycle: z.array(z.object({
605
- name: z.string(),
606
- kind: z.string(),
607
- status: z.string(),
608
- generation_before: z.number(),
609
- })),
610
- fresh: z.array(z.object({ name: z.string(), kind: z.string(), generation: z.number() })),
611
- refused: z.array(z.object({ key: z.string(), reason: z.string() })),
612
- fanout: fleetReportFanout,
613
- });
614
- /**
615
- * `GET /api/config/profiles/{name}/versions` — version METADATA only (action=read;
616
- * no bodies), the generic versioned-store row minus `body`. `is_current` flags the
617
- * active pointer.
618
- */
619
- export const settingsProfileVersionMeta = z.object({
620
- version: z.number(),
621
- tags: z.array(z.string()),
622
- created_at: z.string(),
623
- is_current: z.boolean(),
624
- });
625
- export const settingsProfileVersionList = z.array(settingsProfileVersionMeta);
626
- /**
627
- * `GET /api/config/profiles/{name}/versions/{version}` — one immutable version WITH
628
- * its `body` (action=secret; body rendered masked per the secret-mask union). The generic
629
- * versioned-store row shape.
630
- */
631
- export const settingsProfileVersion = settingsProfileVersionMeta.extend({
632
- body: settingsProfileBody,
633
- });
634
- // -- connectors --------------------------------------------------------------
635
- export const subServiceView = z.object({
636
- id: z.string(),
637
- display_name: z.string(),
638
- description: z.string(),
639
- scopes: z.array(z.string()),
640
- });
641
- export const configFieldView = z.object({
642
- key: z.string(),
643
- label: z.string(),
644
- target: z.enum(['env', 'header']),
645
- required: z.boolean(),
646
- secret: z.boolean(),
647
- });
648
- export const providerView = z.object({
649
- id: z.string(),
650
- display_name: z.string(),
651
- description: z.string(),
652
- // Required and a real URL: the contract's `ProviderDescriptor.icon_url` runs
653
- // `check_web_url(schemes=("https",))`, which rejects an empty/relative value, so
654
- // an empty or malformed one here is drift and fails the parse loudly.
655
- icon_url: z.url(),
656
- kind: z.enum(['oauth', 'none']),
657
- origin: z.enum(['system', 'community']),
658
- category: z.string(),
659
- sub_services: z.array(subServiceView),
660
- config_fields: z.array(configFieldView),
661
- });
662
- /**
663
- * One `connector_category` grouping row served alongside the catalog: the UI's
664
- * label and sort key for the providers it groups, so the list can group, order,
665
- * and label providers by category without a second read.
666
- */
667
- export const connectorCategoryView = z.object({
668
- id: z.string(),
669
- display_name: z.string(),
670
- sort_order: z.number(),
671
- });
672
- /**
673
- * `GET /api/connectors/providers` — the provider catalog: the providers plus the
674
- * category groupings the UI arranges them under. Reshaped from a bare provider
675
- * array so the category label/order surface rides the same read.
676
- */
677
- export const providers = z.object({
678
- providers: z.array(providerView),
679
- categories: z.array(connectorCategoryView),
680
- });
681
- export const connectionView = z.object({
682
- connection_id: z.string(),
683
- provider_id: z.string(),
684
- alias: z.string(),
685
- kind: z.enum(['oauth', 'none']),
686
- account_identity: z.string().nullable(),
687
- enabled_sub_services: z.array(z.string()),
688
- granted_scopes: z.array(z.string()),
689
- // Sub-services whose MCP server did not answer a live reachability probe.
690
- // Populated only on the single-connection GET (the list projection is
691
- // probe-free and always sends `[]`). Reachability is distinct from
692
- // `auth_health_state`: a healthy connection can still have a down sub-service.
693
- // Defaulted so a projection that omits it (an older worker mid-rollout) still
694
- // parses rather than false-failing the whole view.
695
- unreachable_sub_services: z.array(z.string()).default([]),
696
- auth_health_state: z.enum(['healthy', 'reconnect_required', 'refresh_failing']),
697
- created_at: z.string(),
698
- });
699
- export const connectionsList = z.object({
700
- items: z.array(connectionView),
701
- total: z.number(),
702
- // Count of connections whose `auth_health_state` is not healthy across the whole
703
- // set (independent of any filter/limit) — the attention-badge count. Optional:
704
- // no UI consumes it, and an older worker mid-rollout omits it.
705
- unhealthy: z.number().optional(),
706
- });
707
- // A connector mutation that writes the manifest embeds the mode-wrapped fleet
708
- // `fanout` of the reload it broadcast; it is `null` when the response path mutated no
709
- // manifest (an OAuth START opens a flow before any write). Parsed EXPLICITLY so the
710
- // shared fleet-report handler surfaces a failed propagation on every connector flow —
711
- // zod's unknown-key stripping would otherwise drop it silently.
712
- export const startConnectResult = z.union([
713
- z.object({ flow_id: z.string(), authorize_url: z.string() }),
714
- z.object({
715
- connection_id: z.string(),
716
- added_manifest_entries: z.array(z.string()),
717
- fanout: fleetReportFanout.nullable(),
718
- }),
719
- ]);
720
- // A reconnect START opens an OAuth flow and writes no manifest, so it carries no
721
- // fan-out (the manifest write lands when the flow completes).
722
- export const reconnectResult = z.object({ flow_id: z.string(), authorize_url: z.string() });
723
- export const disconnectResult = z.object({
724
- connection_id: z.string(),
725
- upstream_revoke_outcome: z.enum(['success', 'failed', 'skipped']),
726
- upstream_revoke_status: z.number().nullable(),
727
- removed_manifest_entries: z.array(z.string()),
728
- fanout: fleetReportFanout.nullable(),
729
- });
730
- export const patchSubServicesResult = z.object({
731
- connection_id: z.string(),
732
- enabled_sub_services: z.array(z.string()),
733
- consent_required: z.boolean(),
734
- flow_id: z.string().nullable(),
735
- authorize_url: z.string().nullable(),
736
- added_manifest_entries: z.array(z.string()),
737
- removed_manifest_entries: z.array(z.string()),
738
- // `null` on a consent-only toggle that forks an OAuth flow without a manifest write.
739
- fanout: fleetReportFanout.nullable(),
740
- });
741
- export const oauthCompleteResult = z.discriminatedUnion('kind', [
742
- z.object({
743
- kind: z.literal('success'),
744
- connection_id: z.string(),
745
- return_url: z.string(),
746
- // `null` when completing the flow mutated no manifest (a reconcile that changed
747
- // nothing).
748
- fanout: fleetReportFanout.nullable(),
749
- }),
750
- z.object({ kind: z.literal('failed'), reason: z.string() }),
751
- z.object({ kind: z.literal('cancelled'), message: z.string() }),
752
- ]);
753
- // -- studio plugin registry --------------------------------------------------
754
- export const studioPluginManifest = z.object({
755
- name: z.string(),
756
- version: z.string(),
757
- api_version: z.number(),
758
- entry: z.string(),
759
- integrity: z.record(z.string(), z.string()),
760
- contributions: z.object({
761
- tool_panels: z.record(z.string(), z.string()).default({}),
762
- pages: z.array(z.string()).default([]),
763
- settings_tabs: z.array(z.string()).default([]),
764
- // Optional with a default so a manifest without the field still parses; the
765
- // non-strict object would otherwise SILENTLY STRIP an undeclared field, so a
766
- // server that serves `nav_entries` would never reach the UI.
767
- nav_entries: z.array(z.string()).default([]),
768
- }),
769
- });
770
- export const studioPluginRegistry = z.array(studioPluginManifest);
771
- /**
772
- * The page window every paged read door carries; `next_page` is null on the last
773
- * page. `truncated` is TRUE when the door had more matches than it would scan or
774
- * return under its cap — the UI must surface that LOUDLY, never a silent cut — and
775
- * false whenever the window is exhaustive.
776
- */
777
- const pageWindow = {
778
- total: z.number(),
779
- page: z.number(),
780
- page_size: z.number(),
781
- next_page: z.number().nullable(),
782
- truncated: z.boolean(),
783
- };
784
- // -- interactions ------------------------------------------------------------
785
- // Shapes match the skeleton's interactions SSE contract: the SSE
786
- // `interaction.add` frame carries the question and its answer format; the answer
787
- // door returns { interaction_id, status }. `answered` is not a wire field — it
788
- // is a client-side flag the stream hook flips on an `interaction.answered` event.
789
- export const answerFormat = z.enum(['text', 'confirm', 'select', 'form', 'external']);
790
- /** The kind of a question's display-only media item: a remote/inline image, or a link. */
791
- export const mediaKind = z.enum(['image', 'link']);
792
- /**
793
- * One item of a question's display-only media. Applied PER ITEM by the renderer
794
- * (never as a strict array on the frame): the frame's `media` field is a loose
795
- * `z.array(z.unknown())`, and the renderer `safeParse`s each item with this schema
796
- * so one malformed/hostile item is a loud per-item notice, not a whole-frame parse
797
- * failure that would silently vanish an answerable question.
798
- *
799
- * `caption` is `.nullish()` (absent OR `null` both parse to a caption-less item):
800
- * a caption-less item may arrive with the key omitted OR with an explicit `null`, so
801
- * `.optional()` here would false-fail the explicit `null` and render a good image as
802
- * malformed. `url` and `kind` are the only load-bearing fields; the image
803
- * src scheme gate and the link neutralization are enforced by the renderer.
804
- */
805
- export const interactionMediaItem = z.object({
806
- kind: mediaKind,
807
- url: z.string(),
808
- caption: z.string().nullish(),
809
- });
810
- /**
811
- * One per-send choice for a `form` property whose schema is a string (or array of
812
- * strings). `value` is what the answer carries; `label` (absent OR null both parse
813
- * to no label) is the human text shown in its place. A send may replace a property's
814
- * `enum` this way for one ask without republishing the form. Applied per property by
815
- * the form preview (safeParsed), so a malformed entry is a loud notice, never silent.
816
- */
817
- export const formOption = z.object({
818
- value: z.string(),
819
- label: z.string().nullish(),
820
- });
821
- /**
822
- * Per-send `form` data: `values` prefills top-level properties (keyed by property
823
- * name), `options` supplies per-send choice lists (keyed by property name). Both
824
- * default to empty. The form preview safeParses this off `format_payload.data`, so a
825
- * malformed block is a loud notice rather than a whole-frame parse failure.
826
- */
827
- export const formData = z.object({
828
- values: z.record(z.string(), z.unknown()).default({}),
829
- options: z.record(z.string(), z.array(formOption)).default({}),
830
- });
831
- /**
832
- * One page of a stepped `form`: a `title` and the ordered top-level property names it
833
- * groups. `format_payload.pages` is the ordered list of these; absent = one page. The
834
- * form preview safeParses the list, so a malformed page is a loud notice, never silent.
835
- */
836
- export const formPage = z.object({
837
- title: z.string(),
838
- fields: z.array(z.string()),
839
- });
840
- /** The `form` pages list (`format_payload.pages`), safeParsed as a whole by the preview. */
841
- export const formPages = z.array(formPage);
842
- export const interaction = z.object({
843
- interaction_id: z.string(),
844
- group_id: z.string(),
845
- question: z.string().default(''),
846
- answer_format: answerFormat,
847
- // Format-specific payload: select options, form JSON schema (with optional per-send
848
- // `data` and `pages`), external url. The wire sends `null` for formats that carry
849
- // none (text/confirm); it is normalized to `{}` so consumers always see an object.
850
- format_payload: z
851
- .record(z.string(), z.unknown())
852
- .nullish()
853
- .transform((value) => value ?? {}),
854
- created_at: z.string(),
855
- timeout_at: z.string(),
856
- // Whether the answer body is sensitive and never persisted server-side. Rides
857
- // every add frame; an absent value (older frame) normalizes to false.
858
- sensitive: z.boolean().default(false),
859
- // True only for an external question answered by a signed server-to-server
860
- // callback (never by a human); the frame never carries the verifier object.
861
- // Absent/undefined for every other question.
862
- server_verified: z.boolean().optional(),
863
- // Name of the channel plugin the question was also delivered through (e.g.
864
- // "telegram"); absent when the question lives only in this inbox.
865
- channel: z.string().optional(),
866
- // Interaction attribution, each additive and absent when unset. `recipient` is
867
- // the channel delivery address the question went to; `origin` is the run id of
868
- // the background tool run that asked; `audience` is the user_id the question is
869
- // addressed to. Display/binding data only, never an authorization axis; a
870
- // present non-string is malformed.
871
- recipient: z.string().optional(),
872
- origin: z.string().optional(),
873
- audience: z.string().optional(),
874
- // Display-only media shown WITH the question (images and/or links). Absent when
875
- // the question carries none. Deliberately LOOSE (`z.array(z.unknown())`): each
876
- // item is `safeParse`d per item by the renderer against `interactionMediaItem`,
877
- // so one malformed/hostile item can never fail the whole frame parse and hide an
878
- // answerable question. A present non-array value is still malformed.
879
- media: z.array(z.unknown()).optional(),
880
- });
881
- /** The answer door's response — the blocked caller was woken. */
882
- export const interactionAnswered = z.object({
883
- interaction_id: z.string(),
884
- status: z.string(),
885
- });
886
- /**
887
- * The cancel door's response — a pending ask was WITHDRAWN without an answer (the
888
- * asking flow does not resume). `status` is `"cancelled"`; the shape mirrors the
889
- * answer door's terminal reply, but the door is distinct so it carries its own
890
- * schema.
891
- */
892
- export const interactionCancelled = z.object({
893
- interaction_id: z.string(),
894
- status: z.string(),
895
- });
896
- /**
897
- * A page of pending interactions from `GET /api/interactions?page=&pageSize=`. Each
898
- * item is the same record the stream's `interaction.add` frame carries. The pending
899
- * set is the paged base the tail-only stream applies live deltas over.
900
- */
901
- export const interactionsPage = z.object({
902
- items: z.array(interaction),
903
- ...pageWindow,
904
- });
905
- // -- channels ----------------------------------------------------------------
906
- // The installed channel-plugin catalog: names registered via the manifest's
907
- // channel modules. A deployment with none bound answers questions only in this
908
- // inbox (the Studio default).
909
- export const channels = z.object({
910
- channels: z.array(z.string()),
911
- });
912
- // -- conversations -----------------------------------------------------------
913
- // The cross-channel conversation monitor's READ side: the stored routing rows
914
- // (the route picker) from `GET /api/conversations`, a route's threads from
915
- // `GET /api/conversations/{route}/threads`, and one thread's transcript from
916
- // `GET /api/conversations/{route}/transcript?thread_id=`. Timestamps are float
917
- // epoch seconds, not ISO strings, and both paged doors carry the same window
918
- // fields; the transcript adds the direction it was read in.
919
- /** The inbound door a route is bound to: the authed API, or a channel medium. */
920
- export const conversationDoor = z.enum(['api', 'channel']);
921
- /** What a route's turn runs: a registered agent, or a tool dispatch. */
922
- export const conversationTargetKind = z.enum(['agent', 'tool']);
923
- /**
924
- * A route's default control mode (`initial_mode`) when a thread carries no
925
- * per-thread override: `agent` runs the target turn, `manual` suppresses it for an
926
- * operator to answer. The same value vocabulary as a per-thread mode override, but
927
- * a distinct concept (the route default vs. one thread's override).
928
- */
929
- export const conversationMode = z.enum(['agent', 'manual']);
930
- /**
931
- * Where a record sits between intake and a terminal outcome. `failed` is the one
932
- * the monitor surfaces loudly; `shed` and `silent` are terminal by design and
933
- * never send.
934
- */
935
- export const conversationDeliveryStatus = z.enum([
936
- 'accepted',
937
- 'pending_delivery',
938
- 'provisional',
939
- 'delivered',
940
- 'failed',
941
- 'shed',
942
- 'silent',
943
- ]);
944
- /** The nature of a turn's outcome, orthogonal to where its delivery stands. */
945
- export const conversationAnswerStatus = z.enum(['answered', 'error', 'silent']);
946
- /**
947
- * Who authored a record's outgoing side. `client` is the ordinary turn the flow
948
- * answered; `operator` is a message a human sent into the thread, whose text
949
- * rides `answer` (its `inbound_text` is empty).
950
- */
951
- export const conversationRecordOrigin = z.enum(['client', 'operator']);
952
- export const conversationRoutes = z.object({
953
- items: z.array(conversationRoute),
954
- total: z.number(),
955
- });
956
- /**
957
- * The create/replace reply: whether THIS call created the row (vs. replaced an
958
- * existing one), the row itself (its `callback_secret` withheld), and the
959
- * `callback_secret` returned ONCE for an `api`-door row (`null` for a `channel`
960
- * row). The secret signs delivery callbacks and is never re-read from any door, so
961
- * a caller that needs it must capture it from this reply.
962
- */
963
- export const conversationRouteWritten = z.object({
964
- created: z.boolean(),
965
- route_name: z.string(),
966
- route: conversationRoute,
967
- callback_secret: z.string().nullable(),
968
- });
969
- /**
970
- * The delete reply: `removed` says whether THIS call removed the routing row (a
971
- * retryable reclamation of orphaned thread indexes answers `false` rather than a
972
- * 404).
973
- */
974
- export const conversationRouteDeleted = z.object({
975
- removed: z.boolean(),
976
- route_name: z.string(),
977
- });
978
- /**
979
- * One thread of a route, summarized from its newest record. A `thread_id` holds
980
- * an api-door address (`{principal}/{end user}`, percent-encoded), so it never
981
- * goes back into a URL as a path segment — the transcript door takes it as a
982
- * query value.
983
- */
984
- export const conversationThread = z.object({
985
- thread_id: z.string(),
986
- client_address: z.string(),
987
- last_activity_at: z.number(),
988
- message_count: z.number(),
989
- last_delivery_status: conversationDeliveryStatus,
990
- });
991
- export const conversationThreadsPage = z.object({
992
- items: z.array(conversationThread),
993
- ...pageWindow,
994
- });
995
- /**
996
- * One exchange: the visitor's `inbound_text` — every record answers a message, so
997
- * both projections always carry it — and the agent's `answer`, plus where that
998
- * answer's delivery stands. The fields after `updated_at` are ADMIN ONLY —
999
- * the same door serves a caller-scoped projection that withholds them — so they
1000
- * are optional here and absence means "not published to this reader".
1001
- */
1002
- export const conversationMessage = z.object({
1003
- message_id: z.string(),
1004
- route_name: z.string(),
1005
- door: conversationDoor,
1006
- thread_id: z.string(),
1007
- client_address: z.string(),
1008
- caller_principal: z.string().nullable(),
1009
- inbound_text: z.string(),
1010
- answer_status: conversationAnswerStatus.nullable(),
1011
- answer: z.string().nullable(),
1012
- origin: conversationRecordOrigin,
1013
- delivery_status: conversationDeliveryStatus,
1014
- created_at: z.number(),
1015
- updated_at: z.number(),
1016
- channel: z.string().nullable().optional(),
1017
- our_identity: z.string().nullable().optional(),
1018
- provider_message_id: z.string().nullable().optional(),
1019
- callback_url: z.string().nullable().optional(),
1020
- error: z.string().nullable().optional(),
1021
- outbound_message_ids: z.array(z.string()).optional(),
1022
- attempts: z.number().optional(),
1023
- });
1024
- /**
1025
- * The direction a transcript page reads in. `asc` is the reading order (oldest
1026
- * first); `desc` is the live-tail order, where page 1 is always the newest page
1027
- * and paging forward walks BACKWARDS through the thread's history.
1028
- */
1029
- export const transcriptOrder = z.enum(['asc', 'desc']);
1030
- /** A transcript page, echoing the order it was read in. */
1031
- export const conversationTranscriptPage = z.object({
1032
- items: z.array(conversationMessage),
1033
- ...pageWindow,
1034
- order: transcriptOrder,
1035
- });
1036
- /**
1037
- * A route-scoped message search (`GET /api/conversations/{route}/messages/search?q`):
1038
- * every record on the route whose text matches `q`, across threads, newest first.
1039
- * The record shape is the transcript's exactly, so a hit renders with the same
1040
- * projection. `truncated` says the match set outran the door's scan cap — surfaced
1041
- * loudly, never a silent cut.
1042
- */
1043
- export const conversationMessageSearchPage = z.object({
1044
- items: z.array(conversationMessage),
1045
- ...pageWindow,
1046
- });
1047
- /**
1048
- * Who answers a thread's incoming messages: `agent` lets the flow reply on its
1049
- * own; `manual` holds the flow back so a human answers. `source` says whether the
1050
- * setting is the thread's own (`thread`) or inherited from its route (`route`).
1051
- */
1052
- export const conversationThreadMode = z.enum(['agent', 'manual']);
1053
- export const conversationThreadModeState = z.object({
1054
- mode: conversationThreadMode,
1055
- source: z.enum(['thread', 'route']),
1056
- });
1057
- /** The receipt a thread-message write returns: the stored id and its thread. */
1058
- export const conversationThreadMessageSent = z.object({
1059
- message_id: z.string(),
1060
- thread_id: z.string(),
1061
- });
1062
- /** Every stored per-target config (`GET /api/conversation-configs`). */
1063
- export const conversationConfigs = z.object({
1064
- items: z.array(targetConversationConfig),
1065
- total: z.number(),
1066
- });
1067
- /**
1068
- * The upsert reply: whether THIS call created the config (vs. replaced an existing
1069
- * one), its key, and the stored row.
1070
- */
1071
- export const conversationConfigWritten = z.object({
1072
- created: z.boolean(),
1073
- target_kind: conversationTargetKind,
1074
- target_name: z.string(),
1075
- config: targetConversationConfig,
1076
- });
1077
- /** The config-delete reply: `removed` is always `true` on success (an unknown key is a 404). */
1078
- export const conversationConfigDeleted = z.object({
1079
- removed: z.boolean(),
1080
- target_kind: conversationTargetKind,
1081
- target_name: z.string(),
1082
- });
1083
- /**
1084
- * The admin-only failed-delivery listing (`GET /api/conversations/messages/failed`):
1085
- * every answer record whose delivery ended `failed`, across every route and caller.
1086
- * The records are the ADMIN projection (delivery bookkeeping and `error` included),
1087
- * so the row shape is {@link conversationMessage} exactly. It is NOT a paged window —
1088
- * the door returns `{items, total}` and nothing more.
1089
- */
1090
- export const conversationFailedMessages = z.object({
1091
- items: z.array(conversationMessage),
1092
- total: z.number(),
1093
- });
1094
- /**
1095
- * The thread-delete reply (`DELETE /api/conversations/{route_name}/thread?thread_id=`).
1096
- * `removed` is a COUNT of the answer records this call deleted — `0` when a prior
1097
- * run already cleared them, when they had aged out under retention, or when the id
1098
- * was never stored (forgetting is absolute, never a 404 on a valid id).
1099
- */
1100
- export const conversationThreadDeleted = z.object({
1101
- removed: z.number(),
1102
- route_name: z.string(),
1103
- thread_id: z.string(),
1104
- });
1105
- /**
1106
- * The person-erase reply (`DELETE /api/conversations/persons/{person_id}`).
1107
- * `removed` counts the answer records deleted across the person's routes; `erased`
1108
- * says whether THIS call removed the person row (`false` on a retry or an
1109
- * already-gone person — never a 404).
1110
- */
1111
- export const conversationPersonDeleted = z.object({
1112
- person_id: z.string(),
1113
- removed: z.number(),
1114
- erased: z.boolean(),
1115
- });
1116
- // -- channel-web entry gate --------------------------------------------------
1117
- // The web channel's entry gate: a web route can be gated so its chat page is
1118
- // served only to a navigation carrying a live entry code. These four doors are
1119
- // keyed by the route's `our_identity`. A raw code exists only in flight (the
1120
- // mint reply); a listed code carries its hash id, never a raw value (none is
1121
- // stored).
1122
- /** One minted entry code as the gate read door lists it — its hash id, its
1123
- * optional label, and when it was created / dies. Never a raw code. */
1124
- export const webEntryCode = z.object({
1125
- code_id: z.string(),
1126
- label: z.string().nullable(),
1127
- created_at: z.string(),
1128
- expires_at: z.string().nullable(),
1129
- });
1130
- /** `GET /api/channels/web/gates/{identity}` — the gate flag and its live codes. */
1131
- export const webEntryGate = z.object({
1132
- enabled: z.boolean(),
1133
- codes: z.array(webEntryCode),
1134
- });
1135
- /** `PUT /api/channels/web/gates/{identity}` — the gate flag after the write. */
1136
- export const webEntryGateState = z.object({ enabled: z.boolean() });
1137
- /**
1138
- * `POST /api/channels/web/gates/{identity}/codes` — a freshly minted code. The
1139
- * raw `code` rides this reply ONCE (nothing else stores or lists it — a listed
1140
- * code's raw value is unrecoverable by design); `code_id` is its hash id and
1141
- * `expires_at` an ISO-8601 instant, or `null` for a code that never expires.
1142
- */
1143
- export const webEntryCodeMinted = z.object({
1144
- code: z.string(),
1145
- code_id: z.string(),
1146
- expires_at: z.string().nullable(),
1147
- });
1148
- /** `DELETE /api/channels/web/gates/{identity}/codes/{code_id}` — the revoked code. */
1149
- export const webEntryCodeRevoked = z.object({ status: z.literal('revoked') });
1150
- // -- notifications -----------------------------------------------------------
1151
- // The internal notifications sink: the messages the `notify_user` operation records
1152
- // with no channel, so they land only in the Studio inbox. Each record carries the
1153
- // server-minted id + timestamp; `recipient` is null when the message names none.
1154
- // The sink also stores the richer-send forms a notify carried — `media`
1155
- // (images/links shown WITH the message), `template` (a pre-approved out-of-window
1156
- // send), `options` (tappable option labels) — plus the `audience` identity the
1157
- // record is addressed to; the inbox renders them.
1158
- export const notification = z.object({
1159
- id: z.string(),
1160
- message: z.string(),
1161
- // A channel DELIVERY address the message went to; null when the send named none.
1162
- recipient: z.string().nullable(),
1163
- // The IDENTITY (a user_id) whose in-app inbox the record is addressed to, distinct
1164
- // from `recipient`. `.nullish()` accepts both an older record that predates the
1165
- // field (key omitted) and a broadcast send (explicit null) — both parse to "none".
1166
- audience: z.string().nullish(),
1167
- // Display-only media stored WITH the message (images and/or links). Deliberately
1168
- // LOOSE (`z.array(z.unknown())`), like the interactions frame: each item is
1169
- // `safeParse`d per item by the renderer against `interactionMediaItem`, so one
1170
- // malformed/hostile item is a loud per-item notice, never a whole-feed parse
1171
- // failure that would silently vanish every other notification. `.nullish()` covers
1172
- // an older record (key omitted) and a plain send (explicit null).
1173
- media: z.array(z.unknown()).nullish(),
1174
- // A pre-approved template the notify carried, parsed strictly: a drifting one is a
1175
- // loud feed-level `ApiSchemaError`, consistent with the record contract.
1176
- template: channelTemplate.nullish(),
1177
- // Tappable option labels the notify offered; display-only in the operator inbox
1178
- // (there is no conversation for the sink to enter). Strictly a string list.
1179
- options: z.array(z.string()).nullish(),
1180
- created_at: z.string(),
1181
- });
1182
- export const notifications = z.object({
1183
- notifications: z.array(notification),
1184
- });
1185
- // -- hooks -------------------------------------------------------------------
1186
- // The hand-written hook response DTOs: the fire-door authority enum, the list rows and
1187
- // their wrapper, and the per-topic verifier/trigger metadata. The served hook DOCUMENT
1188
- // schemas (`hookSubject`/`hookParams`/`hookRegister`) are generated from the contract
1189
- // bundle and re-exported at the top of this file, not defined here.
1190
- /** A fire door — who may trigger a path, not what the fire may do. A string enum. */
1191
- export const triggerAuth = z.enum([
1192
- 'public',
1193
- 'verifier',
1194
- 'token',
1195
- 'token+api_key',
1196
- 'out-of-service',
1197
- ]);
1198
- export const hookList = z.object({
1199
- items: z.array(hookParams),
1200
- total: z.number(),
1201
- // Per-topic verifier bindings: the topic name maps to the verifier bound to it
1202
- // and that verifier's config (which carries a `secret_env` name, never a secret
1203
- // value). Tolerant of an older/empty response, which omits the key entirely.
1204
- topic_verifiers: z
1205
- .record(z.string(), z.object({ verifier: z.string(), config: z.record(z.string(), z.unknown()) }))
1206
- .default({}),
1207
- // Per-topic fire door (topic → door). Tolerant of an older response omitting it.
1208
- trigger_auth: z.record(z.string(), triggerAuth).default({}),
1209
- });
1210
- export const hookRegistered = z.object({
1211
- registered: z.boolean(),
1212
- name: z.string(),
1213
- });
1214
- export const hookRemoved = z.object({
1215
- removed: z.boolean(),
1216
- name: z.string(),
1217
- });
1218
- // The registered webhook-verifier catalog (`GET /api/hooks/verifiers`) — the
1219
- // sorted verifier NAMES only, never any verifier's config. An empty registry is a
1220
- // valid empty array. This is the ONLY source the topic-verifier bind picker reads.
1221
- export const hookVerifiers = z.array(z.string());
1222
- /** `PUT /api/hooks/topics/{topic}/verifier` — the bound topic + verifier name. */
1223
- export const topicVerifierSet = z.object({ topic: z.string(), verifier: z.string() });
1224
- /** `DELETE /api/hooks/topics/{topic}/verifier` — the unbound topic. */
1225
- export const topicVerifierRemoved = z.object({ removed: z.boolean(), topic: z.string() });
1226
- // -- trigger links -----------------------------------------------------------
1227
- // A trigger link is a minted, token-bearing PUBLIC URL (`GET|POST /trigger/{token}`)
1228
- // that resolves to a hook TOPIC and fires it. Studio mints, lists, and revokes them
1229
- // on the hooks page; the QR encodes the composed absolute URL.
1230
- /**
1231
- * `POST /api/hooks/trigger-links` — a freshly minted trigger link. `trigger_path`
1232
- * is a relative path (`/trigger/<token>`, never an absolute URL — Studio composes
1233
- * the API origin); `token` is the raw token returned exactly ONCE, in this response
1234
- * (nothing else stores or lists it — a listed link's QR is unrecoverable by
1235
- * design). `expires_at` is an ISO-8601 instant, or `null` for a permanent link.
1236
- */
1237
- export const triggerLinkCreated = z.object({
1238
- name: z.string(),
1239
- trigger_path: z.string(),
1240
- token: z.string(),
1241
- topic: z.string(),
1242
- expires_at: z.string().nullable(),
1243
- });
1244
- /**
1245
- * One listed trigger-link record (`GET /api/hooks/trigger-links` item). `tool_kwargs`
1246
- * is the per-link params merged last into every fire (`null` or `{}` = none);
1247
- * `created_by` is the ambient creator identity (`null` on an identity-less,
1248
- * gate-off deployment); `token_hash_prefix` is a short hash prefix for log
1249
- * correlation — never a raw token (none is stored).
1250
- */
1251
- export const triggerLinkRecord = z.object({
1252
- name: z.string(),
1253
- topic: z.string(),
1254
- execution_key: z.string().min(1),
1255
- trigger_auth: triggerAuth,
1256
- tool_kwargs: z.record(z.string(), z.unknown()).nullable(),
1257
- created_by: z.string().nullable(),
1258
- created_at: z.string(),
1259
- expires_at: z.string().nullable(),
1260
- token_hash_prefix: z.string(),
1261
- });
1262
- /** `GET /api/hooks/trigger-links` — every live trigger-link record. */
1263
- export const triggerLinkList = z.object({
1264
- items: z.array(triggerLinkRecord),
1265
- total: z.number(),
1266
- });
1267
- /** `DELETE /api/hooks/trigger-links/{name}` — the revoked link. */
1268
- export const triggerLinkDeleted = z.object({ removed: z.boolean(), name: z.string() });
1269
- // -- settings schema ---------------------------------------------------------
1270
- // The settings form is auto-rendered from a declarative group/field description
1271
- // the skeleton emits from its typed settings models.
1272
- export const settingsSchema = z.object({
1273
- groups: z.array(z.object({
1274
- name: z.string(),
1275
- module: z.string(),
1276
- qualname: z.string(),
1277
- fields: z.array(z.object({
1278
- name: z.string(),
1279
- env_var: z.string(),
1280
- type: z.string(),
1281
- default: jsonValue.nullable(),
1282
- required: z.boolean(),
1283
- secret: z.boolean(),
1284
- description: z.string().nullable(),
1285
- nested_group: z.string().nullable(),
1286
- default_namespace_var: z.string().nullable(),
1287
- value: jsonValue.nullable(),
1288
- })),
1289
- })),
1290
- });
1291
- // -- auth: scopes + api keys -------------------------------------------------
1292
- /** `{ url: scope_id }` — every URL currently mapped to a scope. */
1293
- export const authScopes = z.record(z.string(), z.string());
1294
- export const addUrlToScopeResult = z.object({ scope_id: z.string(), url: z.string() });
1295
- export const removeUrlFromScopeResult = z.object({ url: z.string() });
1296
- export const removeScopeResult = z.object({ scope_id: z.string(), deleted_keys: z.number() });
1297
- /**
1298
- * A route's authorization ACTION class, joined onto the catalog from the route
1299
- * registry. `read`/`write` routes are GRANTABLE — a role's per-tag level opens
1300
- * them; `fenced`/`secret` routes are ADMIN-ONLY and never grantable (no per-tag
1301
- * level reaches them). `null` marks a path the registry carries no metadata for
1302
- * (an unregistered/ungated path — no feature tags, no action).
1303
- */
1304
- export const routeAction = z.enum(['read', 'write', 'fenced', 'secret']);
1305
- /**
1306
- * One row of the route catalog (`GET /api/auth/routes`) — a plain HTTP route with
1307
- * its current mapping, JOINED with its route-registry metadata. `mapped` is the
1308
- * scope id, the public marker, or `null` when the path is unmapped (the mapper's
1309
- * "unassigned" bucket source). `methods` is the route's method set with `HEAD`
1310
- * removed. `tags` are the route's feature-group labels, `summary` its one-line
1311
- * description, and `action` its authorization class — the join fields the Roles
1312
- * grant editor reads to derive grantable feature groups and mark the admin-only
1313
- * (fenced/secret) routes it must never offer a grant for. An unregistered path
1314
- * carries `tags: []`, `summary: ''`, `action: null`.
1315
- */
1316
- export const authRoute = z.object({
1317
- path: z.string(),
1318
- methods: z.array(z.string()),
1319
- mapped: z.string().nullable(),
1320
- tags: z.array(z.string()),
1321
- summary: z.string(),
1322
- action: routeAction.nullable(),
1323
- });
1324
- export const authRoutes = z.array(authRoute);
1325
- // -- auth: roles (editable per-tag RBAC) -------------------------------------
1326
- /** A role's per-tag ACCESS LEVEL: `none` (no access), `read`, or `write`. */
1327
- export const grantLevel = z.enum(['none', 'read', 'write']);
1328
- /** A role's editable grant map: feature-group TAG name → the role's access level. */
1329
- export const roleGrants = z.record(z.string(), grantLevel);
1330
- export const roleList = z.array(roleBody);
1331
- /** `DELETE /api/auth/roles/{name}` — the deleted role's name. */
1332
- export const roleDeleted = z.object({ name: z.string(), deleted: z.boolean() });
1333
- /**
1334
- * One immutable role-version row (`GET /api/auth/roles/{name}/versions` →
1335
- * `versions`). `body` is the role body at that version; `is_current` flags the
1336
- * active pointer. Mirrors the generic versioned-store row shape.
1337
- */
1338
- export const roleVersion = z.object({
1339
- version: z.number(),
1340
- body: roleBody,
1341
- tags: z.array(z.string()),
1342
- created_at: z.string(),
1343
- is_current: z.boolean(),
1344
- });
1345
- /**
1346
- * One who/action/before→after audit row (`GET /api/auth/roles/{name}/versions` →
1347
- * `audit`). Its `body` carries the mutation kind, the actor, and the before/after
1348
- * role bodies (both `null` for a create's `before` / a delete's `after`).
1349
- */
1350
- export const roleAuditEvent = z.object({
1351
- version: z.number(),
1352
- body: z.object({
1353
- action: z.string(),
1354
- actor: z.string().nullable(),
1355
- before: jsonValue.nullable(),
1356
- after: jsonValue.nullable(),
1357
- }),
1358
- tags: z.array(z.string()),
1359
- created_at: z.string(),
1360
- is_current: z.boolean(),
1361
- });
1362
- /** `GET /api/auth/roles/{name}/versions` — the append-only history + audit trail. */
1363
- export const roleVersions = z.object({
1364
- versions: z.array(roleVersion),
1365
- audit: z.array(roleAuditEvent),
1366
- });
1367
- /** `GET /api/auth/public-routes` — the sorted urls pinned to the public marker. */
1368
- export const publicRoutes = z.array(z.string());
1369
- /** `POST /api/auth/public-routes` — the pinned url. */
1370
- export const pinPublicResult = z.object({ url: z.string() });
1371
- /** `DELETE /api/auth/public-routes` — the unpinned url (404 when not pinned). */
1372
- export const unpinPublicResult = z.object({ url: z.string() });
1373
- /** The per-key payloads (`GET /api/auth/tokens-payload`). The stable per-mint
1374
- * `key_fingerprint` is nested under `policy_data`; the picker reads it there. */
1375
- export const tokensPayload = z.array(z.object({
1376
- // The value an `execution_key` binding names.
1377
- user_id: z.string().min(1),
1378
- description: z.string(),
1379
- scopes: z.array(z.string()),
1380
- policy_data: jsonValue,
1381
- condition: templatedText.nullable().optional(),
1382
- }));
1383
- /** Mint reply `{ api_key, key_fingerprint }` narrowed to the raw `sk-…` key,
1384
- * returned once at creation and never again. */
1385
- export const createdApiKey = z
1386
- .object({ api_key: z.string(), key_fingerprint: z.string() })
1387
- .transform((minted) => minted.api_key);
1388
- export const editApiKeyResult = z.object({ user_id: z.string(), updated: z.boolean() });
1389
- export const revokeApiKeyResult = z.object({ user_id: z.string(), revoked: z.boolean() });
1390
- // -- login methods (the public sign-in aggregator) ---------------------------
1391
- /**
1392
- * One field of a `form` login method. `secret` fields render as password
1393
- * inputs; `autocomplete` passes through to the input (e.g. "email",
1394
- * "current-password", "new-password").
1395
- */
1396
- export const loginFormField = z.object({
1397
- name: z.string().min(1),
1398
- label: z.string().min(1),
1399
- secret: z.boolean(),
1400
- autocomplete: z.string().optional(),
1401
- });
1402
- /**
1403
- * The two — and only two — login-method shapes. Discriminated on `shape`; an
1404
- * unknown shape fails validation loudly (contract drift, not a soft skip).
1405
- * Optional fields are `.optional()` (absent), never `.nullable()`: the server
1406
- * serializes with `exclude_none`, so an absent field is OMITTED, never `null`.
1407
- */
1408
- export const loginMethod = z.discriminatedUnion('shape', [
1409
- z.object({
1410
- shape: z.literal('form'),
1411
- id: z.string().min(1),
1412
- title: z.string().min(1),
1413
- purpose: z.enum(['login', 'bootstrap', 'invite']).default('login'),
1414
- fields: z.array(loginFormField).min(1),
1415
- submit_path: z.string().min(1),
1416
- }),
1417
- z.object({
1418
- shape: z.literal('button'),
1419
- id: z.string().min(1),
1420
- label: z.string().min(1),
1421
- icon: z.string().optional(),
1422
- href: z.string().min(1),
1423
- }),
1424
- ]);
1425
- /**
1426
- * `GET /api/login/methods` (PUBLIC). `bootstrap: true` ⇒ the deployment has zero
1427
- * accounts and `methods` contains the owner-creation form. Non-strict — the
1428
- * skeleton may grow additive fields.
1429
- */
1430
- export const loginMethods = z.object({
1431
- methods: z.array(loginMethod),
1432
- bootstrap: z.boolean(),
1433
- });
1434
- /**
1435
- * A successful login/exchange: the minted session token (opaque, `tai-sess-`
1436
- * prefixed — the client treats it as an opaque string) + its user.
1437
- */
1438
- export const loginResult = z.object({
1439
- token: z.string().min(1),
1440
- user_id: z.string().min(1),
1441
- });
1442
- // -- auth: the caller's capability projection (GET /api/auth/me) --------------
1443
- /** A concrete route the caller can reach, with the methods that pass its jq fence. */
1444
- export const routeEntry = z.object({
1445
- path: z.string(),
1446
- methods: z.array(z.string()),
1447
- });
1448
- /**
1449
- * A dynamic route pattern the caller can reach — a mount/pattern surface not
1450
- * enumerable into concrete paths, projected only when its scope AND jq admit it.
1451
- */
1452
- export const patternEntry = z.object({
1453
- pattern: z.string(),
1454
- scope_id: z.string(),
1455
- });
1456
- /**
1457
- * A sub-MCP mount the caller can reach, with the tools it exposes and its
1458
- * transport. Shares the {@link subMcpMount} shape with the registry list, adding
1459
- * the `slug` the projection carries inline (the list keys mounts by slug instead).
1460
- */
1461
- export const subMcpEntry = subMcpMount.extend({ slug: z.string() });
1462
- /**
1463
- * `GET /api/auth/me` — the caller's derived capability projection: the concrete
1464
- * (path, method) surface, dynamic patterns, sub-MCP mounts, tools, and agents it
1465
- * can reach RIGHT NOW (derived server-side, never stored). `admin` is the
1466
- * condition-free ownerless `"*"` discriminator (a TOTAL projection); a scoped
1467
- * session carries `admin: false` and a jq-exact `routes` list. `owner_user_id` is
1468
- * the key's owner claim, `null` for an ownerless key. The invariant is
1469
- * projection ⊆ gate: every projected surface is one the server would admit, so
1470
- * the UI can filter on it without ever advertising a door the gate denies.
1471
- */
1472
- export const meProjection = z.object({
1473
- user_id: z.string(),
1474
- owner_user_id: z.string().nullable(),
1475
- admin: z.boolean(),
1476
- scopes: z.array(z.string()),
1477
- routes: z.array(routeEntry),
1478
- route_patterns: z.array(patternEntry),
1479
- sub_mcp: z.array(subMcpEntry),
1480
- tools: z.array(z.string()),
1481
- agents: z.array(z.string()),
1482
- mintable: z.boolean(),
1483
- });
1484
- /**
1485
- * `POST /api/auth/claim-links` — a one-time claim link minted in the key-create
1486
- * flow. `claim_path` is a fragment-carrier path (`/login#claim=<token>`, never an
1487
- * absolute URL — the Studio composes the origin); `token` is the raw claim token
1488
- * returned exactly ONCE; `expires_at` is an ISO-8601 instant.
1489
- */
1490
- export const claimLinkCreated = z.object({
1491
- claim_path: z.string(),
1492
- token: z.string(),
1493
- expires_at: z.string(),
1494
- });
1495
- /**
1496
- * `POST /api/auth/logout` — the single authed logout dispatcher's result.
1497
- * `revoked` is `true` when a live accounts session was revoked; a plain `sk-` key
1498
- * has nothing to revoke and answers `404` (a loud absent-session signal), never a
1499
- * `revoked: false` body. Non-strict, so a SUCCESSFUL logout never throws
1500
- * `ApiSchemaError` on an additive field.
1501
- */
1502
- export const logoutResult = z.object({ revoked: z.boolean() });
1503
- /**
1504
- * `GET /api/auth/capabilities` — whether this deployment can MINT API keys
1505
- * locally. `mintable: false` means every configured identity provider is
1506
- * validator-only (keys are issued at an external issuer), so the key-creation
1507
- * UI disables up front instead of surfacing a raw mint failure. Non-strict.
1508
- */
1509
- export const authCapabilities = z.object({
1510
- mintable: z.boolean(),
1511
- providers: z.array(z.object({ name: z.string(), mintable: z.boolean() })),
1512
- });
1513
- // -- access-control policy (authoring + versioning) --------------------------
1514
- /**
1515
- * `POST /api/auth/validate-condition` — the fail-closed jq guard. `ok` is the
1516
- * compile/render result; `result` is the boolean of a sample evaluation, or
1517
- * `null` when no `sample_context` was supplied (compile-only). A broken condition
1518
- * is a `400 {error}` surfaced by the transport, NEVER a false `ok` — so a
1519
- * syntactically-broken condition can be caught before it locks a key out. A drift
1520
- * throws `ApiSchemaError`.
1521
- */
1522
- export const validateConditionResult = z.object({
1523
- ok: z.boolean(),
1524
- result: z.boolean().nullable(),
1525
- });
1526
- /**
1527
- * One immutable policy version row
1528
- * (`GET /api/auth/api-keys/{user_id}/policy/versions`). `is_current` flags the
1529
- * active pointer; `tags` is the generic per-version label list (kind-agnostic),
1530
- * mirroring the preset version shape.
1531
- */
1532
- export const policyVersion = z.object({
1533
- version: z.number(),
1534
- body: policyBody,
1535
- tags: z.array(z.string()),
1536
- created_at: z.string(),
1537
- is_current: z.boolean(),
1538
- });
1539
- export const policyVersionList = z.array(policyVersion);
1540
- /** `POST /api/auth/api-keys/{user_id}/policy/rollback` — the re-pointed version. */
1541
- export const policyRollback = z.object({ user_id: z.string(), active_version: z.number() });
1542
- // -- backup ------------------------------------------------------------------
1543
- export const backupSections = z.array(z.object({ name: z.string(), secret: z.boolean() }));
1544
- /** The exported backup document — validated when the UI reads a picked file. */
1545
- export const backupDocument = z.object({
1546
- version: z.literal(1),
1547
- created_at: z.string(),
1548
- sections: z.record(z.string(), z.unknown()),
1549
- errors: z.record(z.string(), z.string()).optional(),
1550
- });
1551
- export const backupImportReport = z.object({
1552
- ok: z.boolean(),
1553
- sections: z.record(z.string(), z.object({
1554
- created: z.number(),
1555
- updated: z.number(),
1556
- skipped: z.number(),
1557
- errors: z.array(z.string()),
1558
- new_api_keys: z
1559
- .array(z.object({
1560
- user_id: z.string(),
1561
- description: z.string(),
1562
- api_key: z.string(),
1563
- }))
1564
- .optional(),
1565
- // The `manifest` and `env` sections apply through the config pipeline, so their
1566
- // report carries the mode-wrapped fleet `fanout` of the restore's reload; other
1567
- // sections omit it. Parsed EXPLICITLY so the shared fleet-report handler can
1568
- // surface a failed restore propagation — otherwise zod would strip it silently.
1569
- fanout: fleetReportFanout.optional(),
1570
- })),
1571
- });
1572
- // -- schedules ---------------------------------------------------------------
1573
- // The skeleton returns opaque backend-tool results; the table reads a few known
1574
- // fields and passes the rest through untouched.
1575
- export const scheduleItem = z
1576
- .object({
1577
- name: z.string(),
1578
- enabled: z.boolean().optional(),
1579
- schedule: jsonValue.optional(),
1580
- target: jsonValue.optional(),
1581
- args: z.array(jsonValue).optional(),
1582
- kwargs: z.record(z.string(), jsonValue).optional(),
1583
- })
1584
- .loose();
1585
- export const scheduleList = z.array(scheduleItem);
1586
- export const serverDateTime = z
1587
- .object({
1588
- utc: jsonValue,
1589
- local: jsonValue.optional(),
1590
- system: jsonValue.optional(),
1591
- })
1592
- .loose();
1593
- // -- observability -----------------------------------------------------------
1594
- export const dashboardMetrics = z.object({
1595
- summary: z.object({
1596
- totalRuns: z.number(),
1597
- totalCost: z.number(),
1598
- totalTokens: z.number(),
1599
- averageLatencyMs: z.number(),
1600
- avgCostPerRun: z.number(),
1601
- avgTokensPerRun: z.number(),
1602
- timeToFirstTokenMs: z.number().nullable(),
1603
- }),
1604
- timeSeries: z.array(z.object({
1605
- bucket: z.string().nullable(),
1606
- runs: z.number(),
1607
- cost: z.number(),
1608
- avgLatencyMs: z.number(),
1609
- totalTokens: z.number(),
1610
- })),
1611
- byModel: z.array(z.object({
1612
- model: z.string(),
1613
- calls: z.number(),
1614
- cost: z.number(),
1615
- totalTokens: z.number(),
1616
- avgLatencyMs: z.number(),
1617
- })),
1618
- granularity: z.enum(['hour', 'day', 'week']),
1619
- });
1620
- export const run = z.object({
1621
- id: z.string(),
1622
- traceId: z.string(),
1623
- createdAt: z.string().nullable(),
1624
- tags: z.array(z.string()),
1625
- status: z.enum(['error', 'success']),
1626
- cost: z.number().nullable(),
1627
- latencyMs: z.number().nullable(),
1628
- totalTokens: z.number().nullable(),
1629
- inputPreview: jsonValue,
1630
- outputPreview: jsonValue,
1631
- });
1632
- export const runsPage = z.object({
1633
- items: z.array(run),
1634
- page: z.number(),
1635
- nextPage: z.number().nullable(),
1636
- });
1637
- export const runSpan = z.object({
1638
- id: z.string(),
1639
- parentId: z.string().nullable(),
1640
- traceId: z.string().nullable(),
1641
- name: z.string().nullable(),
1642
- type: z.string().nullable(),
1643
- level: z.string().nullable(),
1644
- statusMessage: z.string().nullable(),
1645
- start: z.string().nullable(),
1646
- end: z.string().nullable(),
1647
- model: z.string().nullable(),
1648
- usage: jsonValue.nullable(),
1649
- metadata: jsonValue.nullable(),
1650
- input: jsonValue,
1651
- output: jsonValue,
1652
- nodeId: z.string().nullable(),
1653
- });
1654
- export const runTrace = z.object({
1655
- traceId: z.string(),
1656
- timestamp: z.string().nullable(),
1657
- tags: z.array(z.string()),
1658
- totalCost: z.number().nullable(),
1659
- input: jsonValue,
1660
- output: jsonValue,
1661
- metadata: jsonValue.nullable(),
1662
- spans: z.array(runSpan),
1663
- });
1664
- // -- marketplace -------------------------------------------------------------
1665
- /**
1666
- * The CLOSED HTTP-method enum fixed by the contract's RouteMethod, the one source
1667
- * for every route-method field (declaration and install/preview responses alike):
1668
- * a wire method the contract does not define fails loudly as drift rather than
1669
- * passing through silently.
1670
- */
1671
- export const routeMethod = z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']);
1672
- /**
1673
- * How the plugin is delivered, derived server-side from whether its spec names a
1674
- * package: `package` is pip-installed, `descriptor` (marketplace `source` `spec`)
1675
- * installs nothing but the manifest entry. A CLOSED enum, so a wire value the
1676
- * server does not derive fails loudly as drift.
1677
- */
1678
- export const marketplaceDelivery = z.enum(['package', 'descriptor']);
1679
- /**
1680
- * The install-provenance vocabulary a listing/version resolves from: a pip index
1681
- * (`pypi`), a git tag (`github`), or a descriptor yml (`spec`). CLOSED, so a wire
1682
- * value outside it fails as drift.
1683
- */
1684
- export const marketplaceSource = z.enum(['pypi', 'github', 'spec']);
1685
- /**
1686
- * One env var an item requires before install: its `name` and whether its value is
1687
- * a `secret` (an OAuth client secret is; a client id or a plain marker var is not).
1688
- * The install dialog seeds each toggle from `secret` and collects the missing ones.
1689
- */
1690
- export const marketplaceRequiredEnvVar = z.object({ name: z.string(), secret: z.boolean() });
1691
- /**
1692
- * One HTTP route an item declares in its `tai-plugin.yml`: a `path` relative to
1693
- * the item's mount base, the `methods` it answers, and whether it is served
1694
- * `public` (without authentication). The absolute path an operator sees is
1695
- * resolved from the base at install time.
1696
- */
1697
- export const marketplaceRouteDecl = z.object({
1698
- path: z.string(),
1699
- methods: z.array(routeMethod),
1700
- public: z.boolean(),
1701
- });
1702
- /**
1703
- * A route-carrying item's declared mount: the default `base` prefix the routes
1704
- * hang off (an operator may remap it at install) and the `paths` it registers.
1705
- */
1706
- export const marketplaceRoutesDecl = z.object({
1707
- base: z.string(),
1708
- paths: z.array(marketplaceRouteDecl),
1709
- });
1710
- /**
1711
- * One contained item of a marketplace plugin's published version: its kind
1712
- * (tool / agent / extension / …), name, description, free-form tags, and the
1713
- * logical group it belongs to (`null` when ungrouped). `routes` is present only
1714
- * on a route-carrying item (a router or channel); absent/null on every other.
1715
- * `required_env` is the env vars the item needs before install — but the REGISTRY's
1716
- * plugin-detail body does NOT carry it per item: required-env is server-computed
1717
- * (`required_env_for_spec`) and rides the install PREVIEW, never the listing detail,
1718
- * so the registry OMITS it here and it parses as `undefined`. Optional (not
1719
- * defaulted) so the type mirrors the wire; the authority the install dialog collects
1720
- * from is the preview's `required_env`/`missing_env`, never this field.
1721
- */
1722
- export const marketplaceItem = z.object({
1723
- kind: z.string(),
1724
- name: z.string(),
1725
- description: z.string(),
1726
- tags: z.array(z.string()),
1727
- group: z.string().nullable(),
1728
- routes: marketplaceRoutesDecl.nullish(),
1729
- required_env: z.array(marketplaceRequiredEnvVar).optional(),
1730
- });
1731
- /**
1732
- * One kind summary of a search row: an item kind, how many UNGROUPED items of
1733
- * that kind the listing's latest published version carries, and their names.
1734
- * The registry orders the array count DESC then kind ASC, and each entry's
1735
- * `names` ASC; the UI renders in that order.
1736
- */
1737
- export const marketplaceSearchKind = z.object({
1738
- kind: z.string(),
1739
- count: z.number(),
1740
- names: z.array(z.string()),
1741
- });
1742
- /**
1743
- * One logical group of a search row: the group name and how many items the
1744
- * listing's latest published version places in it. The registry orders the
1745
- * array count DESC then name ASC; the UI renders in that order.
1746
- */
1747
- export const marketplaceSearchGroup = z.object({
1748
- name: z.string(),
1749
- count: z.number(),
1750
- });
1751
- /**
1752
- * One listing-level search row (`GET /api/marketplace/search`). `ref` is the
1753
- * "namespace/name" install target, so every row carries enough to link to its
1754
- * plugin. `latest_version` is nullable defensively; the search relation only
1755
- * emits listings with a published version. `kinds` summarizes that latest
1756
- * version's UNGROUPED items; `groups` summarizes its logical groups (`[]` when
1757
- * none). Both keys are always present.
1758
- */
1759
- export const marketplaceSearchRow = z.object({
1760
- ref: z.string(),
1761
- namespace: z.string(),
1762
- name: z.string(),
1763
- display_name: z.string().nullable(),
1764
- icon_url: z.string().nullable(),
1765
- // Null for a descriptor listing (`source` `spec`): it names no package.
1766
- package: z.string().nullable(),
1767
- description: z.string(),
1768
- categories: z.array(z.string()),
1769
- tags: z.array(z.string()),
1770
- trust_tier: z.string(),
1771
- pricing: z.string(),
1772
- // A display-only premium flag: a badge, never a payment surface. Nullable
1773
- // + optional: an older registry omits it, and it is absent on non-premium rows.
1774
- premium: z.boolean().nullish(),
1775
- latest_version: z.string().nullable(),
1776
- downloads: z.number(),
1777
- updated_at: z.string(),
1778
- kinds: z.array(marketplaceSearchKind),
1779
- groups: z.array(marketplaceSearchGroup),
1780
- });
1781
- /**
1782
- * One page of listing rows. The wire carries no next-page field — has-next is
1783
- * COMPUTED: `page * page_size < total`.
1784
- */
1785
- export const marketplaceSearchPage = z.object({
1786
- listings: z.array(marketplaceSearchRow),
1787
- total: z.number(),
1788
- page: z.number(),
1789
- page_size: z.number(),
1790
- });
1791
- /**
1792
- * One version of a listing as the versions list carries it (`version`, its
1793
- * publication `status`, the `contract_range` it was validated against, and when
1794
- * it was `published_at`). `contract_range` and `published_at` are null until a
1795
- * version reaches the published state, so both are nullable.
1796
- */
1797
- export const marketplaceVersion = z.object({
1798
- version: z.string(),
1799
- contract_range: z.string().nullable(),
1800
- status: z.string(),
1801
- published_at: z.string().nullable(),
1802
- });
1803
- /**
1804
- * The listing's latest published version as embedded in its detail: the version
1805
- * (with the `marketplaceVersion` lifecycle fields) and the items it contains. The
1806
- * registry's detail body carries NO per-version `delivery` field — delivery is
1807
- * server-computed from whether the spec names a package, and the detail surface
1808
- * derives it from the listing's `package` (null ⇒ `descriptor`, else `package`).
1809
- * Env to collect comes from the install preview (`required_env` / `missing_env`),
1810
- * never from these items.
1811
- */
1812
- export const marketplaceLatestVersion = marketplaceVersion.extend({
1813
- items: z.array(marketplaceItem),
1814
- });
1815
- /** One advisory row; `withdrawn_at` non-null means it no longer applies. */
1816
- export const marketplaceAdvisory = z.object({
1817
- id: z.number(),
1818
- // The "namespace/name" listing ref exactly as the registry serves it — the
1819
- // wire field consumers match installed plugins against.
1820
- listing: z.string(),
1821
- affected_versions: z.string(),
1822
- severity: z.string(),
1823
- summary: z.string(),
1824
- created_at: z.string(),
1825
- withdrawn_at: z.string().nullable(),
1826
- });
1827
- /**
1828
- * A plugin's full detail (`GET /api/marketplace/plugins/{ns}/{name}`): the
1829
- * listing, its latest published version (`null` when nothing is published yet,
1830
- * carrying the contained items), and the known version history.
1831
- */
1832
- export const marketplacePluginDetail = z.object({
1833
- namespace: z.string(),
1834
- name: z.string(),
1835
- display_name: z.string().nullable(),
1836
- icon_url: z.string().nullable(),
1837
- // Null for a descriptor listing (`source` `spec`): it names no package.
1838
- package: z.string().nullable(),
1839
- // The install-provenance vocabulary (`pypi` / `github` / `spec`). Nullish: an
1840
- // older registry omits it, and a listing with nothing published carries none.
1841
- source: marketplaceSource.nullish(),
1842
- description: z.string(),
1843
- readme_md: z.string().nullable(),
1844
- license: z.string().nullable(),
1845
- homepage_url: z.string().nullable(),
1846
- repository_url: z.string().nullable(),
1847
- // The marketplace-stored docs-site URL: the store is the source, the UI a
1848
- // link. Nullable + optional: absent on a listing with no published docs.
1849
- docs_url: z.string().nullish(),
1850
- categories: z.array(z.string()),
1851
- tags: z.array(z.string()),
1852
- trust_tier: z.string(),
1853
- pricing: z.string(),
1854
- // A display-only premium flag: a badge, never a payment surface.
1855
- premium: z.boolean().nullish(),
1856
- downloads: z.number(),
1857
- latest: marketplaceLatestVersion.nullable(),
1858
- versions: z.array(marketplaceVersion),
1859
- });
1860
- /**
1861
- * One installed plugin's compat verdict against the RUNNING tai42-contract:
1862
- * `compatible` / `incompatible` per its declared contract range, `unknown` when
1863
- * no verdict could be computed. `reason` is the human-readable explanation of a
1864
- * non-`compatible` verdict, `null` when compatible. CLOSED (`.strict()`): the
1865
- * server is built against exactly this shape, so an unknown key is drift and
1866
- * throws instead of being stripped.
1867
- */
1868
- export const marketplaceInstalledCompat = z
1869
- .object({
1870
- status: z.enum(['compatible', 'incompatible', 'unknown']),
1871
- reason: z.string().nullable(),
1872
- })
1873
- .strict();
1874
- /**
1875
- * One installed marketplace plugin as the local attribution store records it.
1876
- * `latest` is the newest registry version (`null` when unknown);
1877
- * `update_available` advertises only a newer COMPATIBLE version, and
1878
- * `incompatible_newer` names the newest version blocked by the running
1879
- * contract (`null` when none), so "an update exists but needs a newer core" is
1880
- * visible. `missing_upstream` flags a plugin the registry no longer lists.
1881
- * `compat` is the row's verdict against the running contract. CLOSED, like
1882
- * every shape of the installed listing.
1883
- */
1884
- export const marketplaceInstalledPlugin = z
1885
- .object({
1886
- ref: z.string(),
1887
- version: z.string(),
1888
- source: z.string(),
1889
- // How the row was delivered: `package` for a pip-installed plugin, `descriptor`
1890
- // for a descriptor-only plugin whose stored spec names no package.
1891
- delivery: marketplaceDelivery,
1892
- installed_at: z.string(),
1893
- latest: z.string().nullable(),
1894
- update_available: z.boolean(),
1895
- incompatible_newer: z.string().nullable(),
1896
- missing_upstream: z.boolean(),
1897
- compat: marketplaceInstalledCompat,
1898
- // The `{kind, name}` of every item this plugin's stored spec provides
1899
- // (local truth). The connectors page's McpServersSection joins the mcp-server
1900
- // item names against the manifest's mcp-entry titles to render an
1901
- // installer-written entry read-only.
1902
- items: z.array(marketplaceItem.pick({ kind: true, name: true })),
1903
- // The persisted `{item_name: base}` mount this plugin is installed at (local
1904
- // truth; `{}` means every item at its declared base). Studio seeds the update
1905
- // flow and renders routes at the ACTUAL mounted base from this.
1906
- route_mounts: z.record(z.string(), z.string()),
1907
- })
1908
- .strict();
1909
- /** One plugin the boot pass quarantined instead of loading, with why. CLOSED. */
1910
- export const marketplaceQuarantinedPlugin = z
1911
- .object({
1912
- name: z.string(),
1913
- reason: z.string(),
1914
- })
1915
- .strict();
1916
- /**
1917
- * The installed inventory (`GET /api/marketplace/installed`): the attributed
1918
- * rows plus every plugin the boot pass quarantined instead of loading. CLOSED.
1919
- */
1920
- export const marketplaceInstalled = z
1921
- .object({
1922
- installed: z.array(marketplaceInstalledPlugin),
1923
- quarantined: z.array(marketplaceQuarantinedPlugin),
1924
- })
1925
- .strict();
1926
- /**
1927
- * One per-plugin outcome of `POST /api/marketplace/upgrade-all`: `upgraded`,
1928
- * already `up-to-date`, `no-compatible-version` in the registry, or `failed`;
1929
- * `detail` always carries the human-readable specifics. CLOSED.
1930
- */
1931
- export const marketplaceUpgradeAllRow = z
1932
- .object({
1933
- ref: z.string(),
1934
- outcome: z.enum(['upgraded', 'up-to-date', 'no-compatible-version', 'failed']),
1935
- detail: z.string(),
1936
- })
1937
- .strict();
1938
- /** The whole upgrade-all readout: one outcome row per installed plugin. CLOSED. */
1939
- export const marketplaceUpgradeAllResult = z
1940
- .object({
1941
- results: z.array(marketplaceUpgradeAllRow),
1942
- })
1943
- .strict();
1944
- /** The advisory state for installed plugins, with when it was last fetched. */
1945
- export const marketplaceAdvisories = z.object({
1946
- advisories: z.array(marketplaceAdvisory),
1947
- fetched_at: z.string(),
1948
- });
1949
- /** The registry's controlled category list, proxied through the skeleton. */
1950
- export const marketplaceCategories = z.array(z.string());
1951
- /** The registry's controlled item-kind list, proxied through the skeleton. */
1952
- export const marketplaceKinds = z.array(z.string());
1953
- /**
1954
- * One route the install / update actually mounted: the item that owns it, the
1955
- * absolute `full_path` it now answers, the `methods`, and whether it is served
1956
- * `public`. The receipt lists these so the operator sees what was opened where.
1957
- */
1958
- export const marketplaceMountedRoute = z.object({
1959
- item: z.string(),
1960
- full_path: z.string(),
1961
- methods: z.array(routeMethod),
1962
- public: z.boolean(),
1963
- });
1964
- /**
1965
- * The receipt of an install / update: what landed and at which version.
1966
- * `notes` (env-selected items naming their activating env var) and any
1967
- * non-critical `advisories` ride BOTH the install and update receipts.
1968
- * `routes` is the mounted-route list — empty for a plugin that registers none.
1969
- * The wire also carries `package`, `reload`, and `pip_output`, which the receipt
1970
- * does not model — zod's default strip drops them; the UI renders the receipt,
1971
- * not the raw install log.
1972
- */
1973
- export const marketplaceInstallResult = z.object({
1974
- ref: z.string(),
1975
- version: z.string(),
1976
- notes: z.array(z.string()),
1977
- advisories: z.array(marketplaceAdvisory),
1978
- routes: z.array(marketplaceMountedRoute),
1979
- });
1980
- /** One resolved route in an install preview: the declared `path`, its resolved
1981
- * absolute `full_path`, the `methods`, and whether it is `public`. */
1982
- export const marketplacePreviewRoute = z.object({
1983
- path: z.string(),
1984
- full_path: z.string(),
1985
- methods: z.array(routeMethod),
1986
- public: z.boolean(),
1987
- });
1988
- /** One route-carrying item in an install preview: its resolved `base` (the
1989
- * override or the default), the `default_base` it declares, and the routes that
1990
- * mount under it. */
1991
- export const marketplacePreviewItem = z.object({
1992
- item: z.string(),
1993
- kind: z.string(),
1994
- base: z.string(),
1995
- default_base: z.string(),
1996
- routes: z.array(marketplacePreviewRoute),
1997
- });
1998
- /** One collision the preview found: a route whose resolved shape+method clashes
1999
- * with an already-owned route. `conflict_owner` is `core` or `plugin:<ref>`; the
2000
- * remedy is to remap the item's base. */
2001
- export const marketplacePreviewCollision = z.object({
2002
- item: z.string(),
2003
- full_path: z.string(),
2004
- methods: z.array(routeMethod),
2005
- conflict_owner: z.string(),
2006
- conflict_path: z.string(),
2007
- });
2008
- /** One public route the operator is asked to accept: served WITHOUT
2009
- * authentication once installed. */
2010
- export const marketplacePreviewPublicRoute = z.object({
2011
- item: z.string(),
2012
- full_path: z.string(),
2013
- methods: z.array(routeMethod),
2014
- });
2015
- /**
2016
- * The install preview (`POST /api/marketplace/install/preview`): the resolved
2017
- * routes per item with any base overrides applied, the collisions against the
2018
- * live registry, the public routes requiring acceptance, and whether acceptance
2019
- * is required at all. `new_public_routes` narrows to rows not already approved
2020
- * (the update case); on a fresh install it equals `public_routes`.
2021
- *
2022
- * `required_env` is every env var the spec requires with its derived secret-ness;
2023
- * `missing_env` is the bare names not already present in the env store union
2024
- * process env (server-computed — the ONE authority the dialog collects), and
2025
- * `delivery` is the one word the surface shows (`package` / `descriptor`).
2026
- */
2027
- export const marketplaceInstallPreview = z.object({
2028
- ref: z.string(),
2029
- version: z.string(),
2030
- items: z.array(marketplacePreviewItem),
2031
- collisions: z.array(marketplacePreviewCollision),
2032
- public_routes: z.array(marketplacePreviewPublicRoute),
2033
- new_public_routes: z.array(marketplacePreviewPublicRoute),
2034
- requires_public_acceptance: z.boolean(),
2035
- required_env: z.array(marketplaceRequiredEnvVar),
2036
- missing_env: z.array(z.string()),
2037
- delivery: marketplaceDelivery,
2038
- });
2039
- /**
2040
- * The receipt of an uninstall. `notes` carries operator warnings (e.g. a config
2041
- * provider still selected by its env var); render them like the install
2042
- * receipt's notes.
2043
- */
2044
- export const marketplaceUninstallResult = z.object({
2045
- ref: z.string(),
2046
- uninstalled: z.literal(true),
2047
- notes: z.array(z.string()),
2048
- });
2049
- // Background tool-run schemas live in their own module; re-exported here so the
2050
- // shared fixture-validation contract resolves them by name alongside the rest.
2051
- export { toolRunSubmitResult, toolRunRecord, toolRunList } from './tool-runs';
2052
- // -- states ------------------------------------------------------------------
2053
- // The hand-written state response DTOs — list rows and detail (built on the generated
2054
- // `stateDeclaration`), attachments, per-subject records and subjects, stats and consumers.
2055
- // The served DOCUMENT schemas (`stateDeclaration`/`stateTemplateDocument` and the template
2056
- // sub-shapes) are generated from the contract bundle and re-exported at the top of this
2057
- // file. The composed `effective_schema` and write `regimes` stay permissive JSON records
2058
- // (the auto-form and JsonTree interpret them at runtime) and are server-computed, so they
2059
- // are modelled optional and a response that omits them still parses.
2060
- /** One addressed subject: the conversation-target scope plus the (kind, key) within it. */
2061
- export const stateSubject = z.object({
2062
- target_kind: conversationTargetKind,
2063
- target_name: z.string(),
2064
- kind: z.string(),
2065
- key: z.string(),
2066
- });
2067
- /** One absolute write-regime rule composed over the attachments: `{path, regime}`, permissive. */
2068
- export const stateRegime = z.record(z.string(), z.unknown());
2069
- /**
2070
- * One row of `GET /api/states` — a served declaration (`list_states` dumps every
2071
- * `StateDeclaration`) plus `updated_at` (the row's last-write timestamp, ISO or
2072
- * `null`). The list carries no record count; the `Records` column reads
2073
- * `getStateStats` lazily per row.
2074
- */
2075
- export const stateListItem = stateDeclaration.extend({
2076
- updated_at: z.string().nullable().default(null),
2077
- });
2078
- export const stateList = z.array(stateListItem);
2079
- /** One template attachment on a state: where the fragment lands + its param/declaration values. */
2080
- export const stateAttachment = z.object({
2081
- template: z.string(),
2082
- path: z.array(z.string()),
2083
- parameters: z.record(z.string(), z.unknown()).default({}),
2084
- declarations: z.record(z.string(), z.unknown()).default({}),
2085
- });
2086
- export const stateAttachmentList = z.array(stateAttachment);
2087
- /** `GET /api/states/{name}` — the declaration (with effective schema + regimes) plus attachments. */
2088
- export const stateDetail = stateDeclaration.extend({
2089
- attachments: z.array(stateAttachment).default([]),
2090
- });
2091
- /**
2092
- * `GET /api/states/{name}/stats` — `records` (total documents), `per_field` (the count
2093
- * of records carrying each base-schema property), `per_kind` (records per subject kind)
2094
- * and `consumers` (the count of listable consumers). The Records tab shows `records`;
2095
- * the states list reads it lazily for its Records column.
2096
- */
2097
- export const stateStats = z.object({
2098
- records: z.number(),
2099
- per_field: z.record(z.string(), z.number()).default({}),
2100
- per_kind: z.record(z.string(), z.number()).default({}),
2101
- consumers: z.number().default(0),
2102
- });
2103
- /**
2104
- * One row of `GET /api/state-templates`. The template document plus the two derived columns
2105
- * the Templates tab shows: `attached_to` (how many states attach it — a delete is refused
2106
- * while > 0) and `shipped_default` (a platform-shipped template). Both are server-derived
2107
- * columns; the document fields are verbatim.
2108
- */
2109
- export const stateTemplateListItem = stateTemplateDocument.extend({
2110
- attached_to: z.number().default(0),
2111
- shipped_default: z.boolean().default(false),
2112
- });
2113
- export const stateTemplateList = z.array(stateTemplateListItem);
2114
- /** A read record: the state, its subject, the document + monotonic seq, and any fold. */
2115
- export const stateRecord = z.object({
2116
- state: z.string(),
2117
- subject: stateSubject,
2118
- data: z.record(z.string(), z.unknown()).default({}),
2119
- seq: z.number(),
2120
- canonical_subject: stateSubject,
2121
- folded_from: z.array(stateSubject).default([]),
2122
- });
2123
- /** The outcome of an `apply` (a delta batch): whether it applied + the resulting doc. */
2124
- export const applyResult = z.object({
2125
- applied: z.boolean(),
2126
- data: z.record(z.string(), z.unknown()).nullable().default(null),
2127
- seq: z.number().nullable().default(null),
2128
- skipped: z.array(z.record(z.string(), z.unknown())).default([]),
2129
- });
2130
- /**
2131
- * `GET …/template-jq/{name}` — the evaluated template jq's `name`, its `purpose`, and
2132
- * its `value` (the `input` jq's read). GET evaluates ONLY an `input`-purpose jq; a GET
2133
- * on an `update`-purpose name is refused with 422, so the result's purpose is always
2134
- * `input`.
2135
- */
2136
- export const templateJqResult = z.object({
2137
- name: z.string(),
2138
- purpose: z.literal('input'),
2139
- value: z.unknown(),
2140
- });
2141
- /**
2142
- * `POST …/template-jq/{name}` — the applied template jq's outcome. The jq lands an op
2143
- * batch through the same `apply` chokepoint as a delta, so `applied`/`data`/`seq`/`skipped`
2144
- * carry that outcome.
2145
- */
2146
- export const templateJqApplyResult = z.object({
2147
- name: z.string(),
2148
- applied: z.boolean(),
2149
- data: z.record(z.string(), z.unknown()).nullable().default(null),
2150
- seq: z.number().nullable().default(null),
2151
- skipped: z.array(z.record(z.string(), z.unknown())).default([]),
2152
- });
2153
- /**
2154
- * One paged subject row: the addressed `subject` plus its record's last-write
2155
- * `updated_at` — epoch seconds (the store's `extract(epoch FROM updated_at)`), served
2156
- * raw (no `mode="json"` dump), and `NOT NULL` on every record, so a plain number.
2157
- */
2158
- export const subjectRow = z.object({
2159
- subject: stateSubject,
2160
- updated_at: z.number(),
2161
- });
2162
- /**
2163
- * `GET /api/states/{name}/subjects` — a keyset page of subject rows (optionally of one
2164
- * `kind`): the matched `subjects` plus the `next_cursor` a "Load more" carries back
2165
- * (`null` at the end).
2166
- */
2167
- export const subjectPage = z.object({
2168
- subjects: z.array(subjectRow),
2169
- next_cursor: z.string().nullable().default(null),
2170
- });
2171
- /**
2172
- * `POST /api/states/{name}/records/search` — a keyset page of the subject rows whose
2173
- * document contains the filters (a JSONB containment match). Each hit's `subject` opens
2174
- * the record page; `next_cursor` pages the rest.
2175
- */
2176
- export const recordSearchPage = z.object({
2177
- matches: z.array(subjectRow),
2178
- next_cursor: z.string().nullable().default(null),
2179
- });
2180
- /** A WriteEntry's origin completed by the platform chokepoint (mirrors CompletedOrigin). */
2181
- export const completedOrigin = z.object({
2182
- consumer: z.string().nullable().default(null),
2183
- // Opaque consumer-supplied provenance JSON the platform stores as is.
2184
- meta: z.record(z.string(), z.unknown()).nullable().default(null),
2185
- run_id: z.string().nullable().default(null),
2186
- op_id: z.string().nullable().default(null),
2187
- door: z.string(),
2188
- actor: z.string().nullable().default(null),
2189
- turn_id: z.string().nullable().default(null),
2190
- inbound_id: z.string().nullable().default(null),
2191
- });
2192
- /** One row of a subject's audit trail (mirrors WriteEntry). `paths` are absolute. */
2193
- export const writeEntry = z.object({
2194
- seq: z.number(),
2195
- at: z.string(),
2196
- origin: completedOrigin,
2197
- paths: z.array(z.array(z.union([z.string(), z.number()]))).default([]),
2198
- });
2199
- /** `GET /api/states/{name}/records/.../writes` — a keyset page of the audit trail. */
2200
- export const writesPage = z.object({
2201
- items: z.array(writeEntry),
2202
- next_cursor: z.string().nullable().default(null),
2203
- });
2204
- /** Where the Studio opens a consumer (mirrors ConsumerLink): a token+search OR plugin path. */
2205
- export const consumerLink = z.object({
2206
- token: z.string().nullable().default(null),
2207
- plugin_path: z.string().nullable().default(null),
2208
- search: z.record(z.string(), z.unknown()).nullable().default(null),
2209
- });
2210
- /**
2211
- * One thing that binds a state (mirrors ConsumerRow): its `kind` (flow / hook / schedule
2212
- * / agent), `name`, human `detail` and optional `link`. `unavailable` marks a consumer
2213
- * family that cannot be listed on this deployment (e.g. no scheduling backend), surfaced
2214
- * as a muted line — never swallowed.
2215
- */
2216
- export const consumerRow = z.object({
2217
- kind: z.string(),
2218
- name: z.string().nullable().default(null),
2219
- detail: z.string().nullable().default(null),
2220
- link: consumerLink.nullable().default(null),
2221
- unavailable: z.string().nullable().default(null),
2222
- });
2223
- /** `GET /api/states/{name}/consumers` — the union of every registered lister's rows. */
2224
- export const stateConsumers = z.array(consumerRow);
2225
- /** `DELETE /api/states/{name}` — the removed state. */
2226
- export const stateDeleted = z.object({ name: z.string(), deleted: z.literal(true) });
2227
- /** `PUT /api/states/{name}/attachments/{template}` — the template now attached to the state. */
2228
- export const stateAttached = z.object({
2229
- attached: z.literal(true),
2230
- state: z.string(),
2231
- template: z.string(),
2232
- });
2233
- /** `PATCH /api/states/{name}/attachments/{template}` — the attachment whose declarations were rewritten. */
2234
- export const stateAttachmentUpdated = z.object({
2235
- updated: z.literal(true),
2236
- state: z.string(),
2237
- template: z.string(),
2238
- });
2239
- /** `DELETE /api/states/{name}/attachments/{template}` — the template detached from the state. */
2240
- export const stateDetached = z.object({
2241
- detached: z.literal(true),
2242
- state: z.string(),
2243
- template: z.string(),
2244
- });
2245
- /**
2246
- * `POST /api/states/{name}/records/.../fold` — the fold report: the `mode`, the
2247
- * `{kind, key}` of the folded `from` and surviving `into` subjects, whether the fold
2248
- * was `already` in place, and how many records were `flattened` into the survivor.
2249
- */
2250
- export const stateFoldReport = z.object({
2251
- mode: z.enum(['switch', 'merge']),
2252
- from: z.object({ kind: z.string(), key: z.string() }),
2253
- into: z.object({ kind: z.string(), key: z.string() }),
2254
- already: z.boolean(),
2255
- flattened: z.number().default(0),
2256
- });
2257
- /** `DELETE /api/state-templates/{name}` — the removed template document. */
2258
- export const stateTemplateDeleted = z.object({ name: z.string(), deleted: z.literal(true) });
2259
- /** `DELETE /api/states/{name}/records/...` — the erased record marker. */
2260
- export const recordErased = z.object({ erased: z.literal(true) });
2261
- /**
2262
- * `POST /api/state-retention/prune` — the retention sweep's per-state deleted counts
2263
- * (`{}` when nothing expired); the UI sums the values for its total.
2264
- */
2265
- export const stateRetentionPruned = z.object({
2266
- pruned: z.record(z.string(), z.number()).default({}),
2267
- });
2268
- //# sourceMappingURL=schemas.js.map