provekit 0.1.0__py3-none-any.whl

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 (485) hide show
  1. provekit/__init__.py +0 -0
  2. provekit/cli.py +256 -0
  3. provekit/config.py +77 -0
  4. provekit/database.py +132 -0
  5. provekit/main.py +115 -0
  6. provekit/migrations/env.py +40 -0
  7. provekit/migrations/script.py.mako +22 -0
  8. provekit/migrations/versions/323eb73d463c_user_email_verified.py +32 -0
  9. provekit/migrations/versions/49e8ab812556_baseline_schema.py +241 -0
  10. provekit/migrations/versions/819ed5ff183e_workspace_ingest_key.py +35 -0
  11. provekit/migrations/versions/a1b2c3d4e5f6_user_token_version.py +27 -0
  12. provekit/models.py +191 -0
  13. provekit/observability.py +154 -0
  14. provekit/routers/__init__.py +0 -0
  15. provekit/routers/auth.py +150 -0
  16. provekit/routers/connections.py +270 -0
  17. provekit/routers/deployments.py +161 -0
  18. provekit/routers/flows.py +188 -0
  19. provekit/routers/library.py +265 -0
  20. provekit/routers/prompts.py +72 -0
  21. provekit/routers/run.py +203 -0
  22. provekit/routers/runtime.py +103 -0
  23. provekit/routers/traces.py +65 -0
  24. provekit/routers/usage.py +42 -0
  25. provekit/services/__init__.py +0 -0
  26. provekit/services/assertions.py +135 -0
  27. provekit/services/auth.py +131 -0
  28. provekit/services/deploy.py +63 -0
  29. provekit/services/dispatch.py +313 -0
  30. provekit/services/email.py +38 -0
  31. provekit/services/flow.py +299 -0
  32. provekit/services/limits.py +109 -0
  33. provekit/services/masking.py +45 -0
  34. provekit/services/netguard.py +69 -0
  35. provekit/services/otel.py +146 -0
  36. provekit/services/promptfoo.py +92 -0
  37. provekit/services/providers/__init__.py +0 -0
  38. provekit/services/providers/a2a_client.py +110 -0
  39. provekit/services/providers/agent_http.py +55 -0
  40. provekit/services/providers/llm.py +364 -0
  41. provekit/services/providers/mcp_client.py +289 -0
  42. provekit/services/runstore.py +93 -0
  43. provekit/services/sealing.py +106 -0
  44. provekit/services/templates.py +69 -0
  45. provekit/services/testfile.py +122 -0
  46. provekit/services/tooling.py +194 -0
  47. provekit/services/workspace.py +91 -0
  48. provekit/templates/flows/_manifest.json +2594 -0
  49. provekit/templates/flows/banking-action-items.yaml +43 -0
  50. provekit/templates/flows/banking-answer.yaml +43 -0
  51. provekit/templates/flows/banking-classify-intent.yaml +43 -0
  52. provekit/templates/flows/banking-draft-critique-revise.yaml +75 -0
  53. provekit/templates/flows/banking-extract-to-json.yaml +43 -0
  54. provekit/templates/flows/banking-faq-match-answer.yaml +60 -0
  55. provekit/templates/flows/banking-keyword-extract.yaml +43 -0
  56. provekit/templates/flows/banking-language-route.yaml +103 -0
  57. provekit/templates/flows/banking-moderation-gate.yaml +73 -0
  58. provekit/templates/flows/banking-redact-summarize.yaml +59 -0
  59. provekit/templates/flows/banking-score-gate.yaml +73 -0
  60. provekit/templates/flows/banking-sentiment-route.yaml +73 -0
  61. provekit/templates/flows/banking-severity-tiers.yaml +103 -0
  62. provekit/templates/flows/banking-summarize-then-decide.yaml +88 -0
  63. provekit/templates/flows/banking-tag-enrich.yaml +43 -0
  64. provekit/templates/flows/banking-tone-rewrite.yaml +43 -0
  65. provekit/templates/flows/banking-translate-reply.yaml +58 -0
  66. provekit/templates/flows/banking-triage-route.yaml +73 -0
  67. provekit/templates/flows/community-forum-action-items.yaml +43 -0
  68. provekit/templates/flows/community-forum-answer.yaml +43 -0
  69. provekit/templates/flows/community-forum-classify-intent.yaml +43 -0
  70. provekit/templates/flows/community-forum-draft-critique-revise.yaml +75 -0
  71. provekit/templates/flows/community-forum-extract-to-json.yaml +43 -0
  72. provekit/templates/flows/community-forum-faq-match-answer.yaml +60 -0
  73. provekit/templates/flows/community-forum-keyword-extract.yaml +43 -0
  74. provekit/templates/flows/community-forum-language-route.yaml +103 -0
  75. provekit/templates/flows/community-forum-moderation-gate.yaml +73 -0
  76. provekit/templates/flows/community-forum-redact-summarize.yaml +59 -0
  77. provekit/templates/flows/community-forum-score-gate.yaml +73 -0
  78. provekit/templates/flows/community-forum-sentiment-route.yaml +73 -0
  79. provekit/templates/flows/community-forum-severity-tiers.yaml +103 -0
  80. provekit/templates/flows/community-forum-summarize-then-decide.yaml +88 -0
  81. provekit/templates/flows/community-forum-tag-enrich.yaml +43 -0
  82. provekit/templates/flows/community-forum-tone-rewrite.yaml +43 -0
  83. provekit/templates/flows/community-forum-translate-reply.yaml +58 -0
  84. provekit/templates/flows/community-forum-triage-route.yaml +73 -0
  85. provekit/templates/flows/content-moderation-action-items.yaml +43 -0
  86. provekit/templates/flows/content-moderation-answer.yaml +43 -0
  87. provekit/templates/flows/content-moderation-classify-intent.yaml +43 -0
  88. provekit/templates/flows/content-moderation-draft-critique-revise.yaml +75 -0
  89. provekit/templates/flows/content-moderation-extract-to-json.yaml +43 -0
  90. provekit/templates/flows/content-moderation-faq-match-answer.yaml +60 -0
  91. provekit/templates/flows/content-moderation-keyword-extract.yaml +43 -0
  92. provekit/templates/flows/content-moderation-language-route.yaml +103 -0
  93. provekit/templates/flows/content-moderation-moderation-gate.yaml +73 -0
  94. provekit/templates/flows/content-moderation-redact-summarize.yaml +59 -0
  95. provekit/templates/flows/content-moderation-score-gate.yaml +73 -0
  96. provekit/templates/flows/content-moderation-sentiment-route.yaml +73 -0
  97. provekit/templates/flows/content-moderation-severity-tiers.yaml +103 -0
  98. provekit/templates/flows/content-moderation-summarize-then-decide.yaml +88 -0
  99. provekit/templates/flows/content-moderation-tag-enrich.yaml +43 -0
  100. provekit/templates/flows/content-moderation-tone-rewrite.yaml +43 -0
  101. provekit/templates/flows/content-moderation-translate-reply.yaml +58 -0
  102. provekit/templates/flows/content-moderation-triage-route.yaml +73 -0
  103. provekit/templates/flows/customer-support-action-items.yaml +43 -0
  104. provekit/templates/flows/customer-support-answer.yaml +43 -0
  105. provekit/templates/flows/customer-support-classify-intent.yaml +43 -0
  106. provekit/templates/flows/customer-support-draft-critique-revise.yaml +75 -0
  107. provekit/templates/flows/customer-support-extract-to-json.yaml +43 -0
  108. provekit/templates/flows/customer-support-faq-match-answer.yaml +60 -0
  109. provekit/templates/flows/customer-support-keyword-extract.yaml +43 -0
  110. provekit/templates/flows/customer-support-language-route.yaml +103 -0
  111. provekit/templates/flows/customer-support-moderation-gate.yaml +73 -0
  112. provekit/templates/flows/customer-support-redact-summarize.yaml +59 -0
  113. provekit/templates/flows/customer-support-score-gate.yaml +73 -0
  114. provekit/templates/flows/customer-support-sentiment-route.yaml +73 -0
  115. provekit/templates/flows/customer-support-severity-tiers.yaml +103 -0
  116. provekit/templates/flows/customer-support-summarize-then-decide.yaml +88 -0
  117. provekit/templates/flows/customer-support-tag-enrich.yaml +43 -0
  118. provekit/templates/flows/customer-support-tone-rewrite.yaml +43 -0
  119. provekit/templates/flows/customer-support-translate-reply.yaml +58 -0
  120. provekit/templates/flows/customer-support-triage-route.yaml +73 -0
  121. provekit/templates/flows/developer-tooling-action-items.yaml +43 -0
  122. provekit/templates/flows/developer-tooling-answer.yaml +43 -0
  123. provekit/templates/flows/developer-tooling-classify-intent.yaml +43 -0
  124. provekit/templates/flows/developer-tooling-draft-critique-revise.yaml +75 -0
  125. provekit/templates/flows/developer-tooling-extract-to-json.yaml +43 -0
  126. provekit/templates/flows/developer-tooling-faq-match-answer.yaml +60 -0
  127. provekit/templates/flows/developer-tooling-keyword-extract.yaml +43 -0
  128. provekit/templates/flows/developer-tooling-language-route.yaml +103 -0
  129. provekit/templates/flows/developer-tooling-moderation-gate.yaml +73 -0
  130. provekit/templates/flows/developer-tooling-redact-summarize.yaml +59 -0
  131. provekit/templates/flows/developer-tooling-score-gate.yaml +73 -0
  132. provekit/templates/flows/developer-tooling-sentiment-route.yaml +73 -0
  133. provekit/templates/flows/developer-tooling-severity-tiers.yaml +103 -0
  134. provekit/templates/flows/developer-tooling-summarize-then-decide.yaml +88 -0
  135. provekit/templates/flows/developer-tooling-tag-enrich.yaml +43 -0
  136. provekit/templates/flows/developer-tooling-tone-rewrite.yaml +43 -0
  137. provekit/templates/flows/developer-tooling-translate-reply.yaml +58 -0
  138. provekit/templates/flows/developer-tooling-triage-route.yaml +73 -0
  139. provekit/templates/flows/devrel-action-items.yaml +43 -0
  140. provekit/templates/flows/devrel-answer.yaml +43 -0
  141. provekit/templates/flows/devrel-classify-intent.yaml +43 -0
  142. provekit/templates/flows/devrel-draft-critique-revise.yaml +75 -0
  143. provekit/templates/flows/devrel-extract-to-json.yaml +43 -0
  144. provekit/templates/flows/devrel-faq-match-answer.yaml +60 -0
  145. provekit/templates/flows/devrel-keyword-extract.yaml +43 -0
  146. provekit/templates/flows/devrel-language-route.yaml +103 -0
  147. provekit/templates/flows/devrel-moderation-gate.yaml +73 -0
  148. provekit/templates/flows/devrel-redact-summarize.yaml +59 -0
  149. provekit/templates/flows/devrel-score-gate.yaml +73 -0
  150. provekit/templates/flows/devrel-sentiment-route.yaml +73 -0
  151. provekit/templates/flows/devrel-severity-tiers.yaml +103 -0
  152. provekit/templates/flows/devrel-summarize-then-decide.yaml +88 -0
  153. provekit/templates/flows/devrel-tag-enrich.yaml +43 -0
  154. provekit/templates/flows/devrel-tone-rewrite.yaml +43 -0
  155. provekit/templates/flows/devrel-translate-reply.yaml +58 -0
  156. provekit/templates/flows/devrel-triage-route.yaml +73 -0
  157. provekit/templates/flows/e-commerce-action-items.yaml +43 -0
  158. provekit/templates/flows/e-commerce-answer.yaml +43 -0
  159. provekit/templates/flows/e-commerce-classify-intent.yaml +43 -0
  160. provekit/templates/flows/e-commerce-draft-critique-revise.yaml +75 -0
  161. provekit/templates/flows/e-commerce-extract-to-json.yaml +43 -0
  162. provekit/templates/flows/e-commerce-faq-match-answer.yaml +60 -0
  163. provekit/templates/flows/e-commerce-keyword-extract.yaml +43 -0
  164. provekit/templates/flows/e-commerce-language-route.yaml +103 -0
  165. provekit/templates/flows/e-commerce-moderation-gate.yaml +73 -0
  166. provekit/templates/flows/e-commerce-redact-summarize.yaml +59 -0
  167. provekit/templates/flows/e-commerce-score-gate.yaml +73 -0
  168. provekit/templates/flows/e-commerce-sentiment-route.yaml +73 -0
  169. provekit/templates/flows/e-commerce-severity-tiers.yaml +103 -0
  170. provekit/templates/flows/e-commerce-summarize-then-decide.yaml +88 -0
  171. provekit/templates/flows/e-commerce-tag-enrich.yaml +43 -0
  172. provekit/templates/flows/e-commerce-tone-rewrite.yaml +43 -0
  173. provekit/templates/flows/e-commerce-translate-reply.yaml +58 -0
  174. provekit/templates/flows/e-commerce-triage-route.yaml +73 -0
  175. provekit/templates/flows/education-action-items.yaml +43 -0
  176. provekit/templates/flows/education-answer.yaml +43 -0
  177. provekit/templates/flows/education-classify-intent.yaml +43 -0
  178. provekit/templates/flows/education-draft-critique-revise.yaml +75 -0
  179. provekit/templates/flows/education-extract-to-json.yaml +43 -0
  180. provekit/templates/flows/education-faq-match-answer.yaml +60 -0
  181. provekit/templates/flows/education-keyword-extract.yaml +43 -0
  182. provekit/templates/flows/education-language-route.yaml +103 -0
  183. provekit/templates/flows/education-moderation-gate.yaml +73 -0
  184. provekit/templates/flows/education-redact-summarize.yaml +59 -0
  185. provekit/templates/flows/education-score-gate.yaml +73 -0
  186. provekit/templates/flows/education-sentiment-route.yaml +73 -0
  187. provekit/templates/flows/education-severity-tiers.yaml +103 -0
  188. provekit/templates/flows/education-summarize-then-decide.yaml +88 -0
  189. provekit/templates/flows/education-tag-enrich.yaml +43 -0
  190. provekit/templates/flows/education-tone-rewrite.yaml +43 -0
  191. provekit/templates/flows/education-translate-reply.yaml +58 -0
  192. provekit/templates/flows/education-triage-route.yaml +73 -0
  193. provekit/templates/flows/finance-action-items.yaml +43 -0
  194. provekit/templates/flows/finance-answer.yaml +43 -0
  195. provekit/templates/flows/finance-classify-intent.yaml +43 -0
  196. provekit/templates/flows/finance-draft-critique-revise.yaml +75 -0
  197. provekit/templates/flows/finance-extract-to-json.yaml +43 -0
  198. provekit/templates/flows/finance-faq-match-answer.yaml +60 -0
  199. provekit/templates/flows/finance-keyword-extract.yaml +43 -0
  200. provekit/templates/flows/finance-language-route.yaml +103 -0
  201. provekit/templates/flows/finance-moderation-gate.yaml +73 -0
  202. provekit/templates/flows/finance-redact-summarize.yaml +59 -0
  203. provekit/templates/flows/finance-score-gate.yaml +73 -0
  204. provekit/templates/flows/finance-sentiment-route.yaml +73 -0
  205. provekit/templates/flows/finance-severity-tiers.yaml +103 -0
  206. provekit/templates/flows/finance-summarize-then-decide.yaml +88 -0
  207. provekit/templates/flows/finance-tag-enrich.yaml +43 -0
  208. provekit/templates/flows/finance-tone-rewrite.yaml +43 -0
  209. provekit/templates/flows/finance-translate-reply.yaml +58 -0
  210. provekit/templates/flows/finance-triage-route.yaml +73 -0
  211. provekit/templates/flows/food-delivery-action-items.yaml +43 -0
  212. provekit/templates/flows/food-delivery-answer.yaml +43 -0
  213. provekit/templates/flows/food-delivery-classify-intent.yaml +43 -0
  214. provekit/templates/flows/food-delivery-draft-critique-revise.yaml +75 -0
  215. provekit/templates/flows/food-delivery-extract-to-json.yaml +43 -0
  216. provekit/templates/flows/food-delivery-faq-match-answer.yaml +60 -0
  217. provekit/templates/flows/food-delivery-keyword-extract.yaml +43 -0
  218. provekit/templates/flows/food-delivery-language-route.yaml +103 -0
  219. provekit/templates/flows/food-delivery-moderation-gate.yaml +73 -0
  220. provekit/templates/flows/food-delivery-redact-summarize.yaml +59 -0
  221. provekit/templates/flows/food-delivery-score-gate.yaml +73 -0
  222. provekit/templates/flows/food-delivery-sentiment-route.yaml +73 -0
  223. provekit/templates/flows/food-delivery-severity-tiers.yaml +103 -0
  224. provekit/templates/flows/food-delivery-summarize-then-decide.yaml +88 -0
  225. provekit/templates/flows/food-delivery-tag-enrich.yaml +43 -0
  226. provekit/templates/flows/food-delivery-tone-rewrite.yaml +43 -0
  227. provekit/templates/flows/food-delivery-translate-reply.yaml +58 -0
  228. provekit/templates/flows/food-delivery-triage-route.yaml +73 -0
  229. provekit/templates/flows/gaming-support-action-items.yaml +43 -0
  230. provekit/templates/flows/gaming-support-answer.yaml +43 -0
  231. provekit/templates/flows/gaming-support-classify-intent.yaml +43 -0
  232. provekit/templates/flows/gaming-support-draft-critique-revise.yaml +75 -0
  233. provekit/templates/flows/gaming-support-extract-to-json.yaml +43 -0
  234. provekit/templates/flows/gaming-support-faq-match-answer.yaml +60 -0
  235. provekit/templates/flows/gaming-support-keyword-extract.yaml +43 -0
  236. provekit/templates/flows/gaming-support-language-route.yaml +103 -0
  237. provekit/templates/flows/gaming-support-moderation-gate.yaml +73 -0
  238. provekit/templates/flows/gaming-support-redact-summarize.yaml +59 -0
  239. provekit/templates/flows/gaming-support-score-gate.yaml +73 -0
  240. provekit/templates/flows/gaming-support-sentiment-route.yaml +73 -0
  241. provekit/templates/flows/gaming-support-severity-tiers.yaml +103 -0
  242. provekit/templates/flows/gaming-support-summarize-then-decide.yaml +88 -0
  243. provekit/templates/flows/gaming-support-tag-enrich.yaml +43 -0
  244. provekit/templates/flows/gaming-support-tone-rewrite.yaml +43 -0
  245. provekit/templates/flows/gaming-support-translate-reply.yaml +58 -0
  246. provekit/templates/flows/gaming-support-triage-route.yaml +73 -0
  247. provekit/templates/flows/healthcare-intake-action-items.yaml +43 -0
  248. provekit/templates/flows/healthcare-intake-answer.yaml +43 -0
  249. provekit/templates/flows/healthcare-intake-classify-intent.yaml +43 -0
  250. provekit/templates/flows/healthcare-intake-draft-critique-revise.yaml +75 -0
  251. provekit/templates/flows/healthcare-intake-extract-to-json.yaml +43 -0
  252. provekit/templates/flows/healthcare-intake-faq-match-answer.yaml +60 -0
  253. provekit/templates/flows/healthcare-intake-keyword-extract.yaml +43 -0
  254. provekit/templates/flows/healthcare-intake-language-route.yaml +103 -0
  255. provekit/templates/flows/healthcare-intake-moderation-gate.yaml +73 -0
  256. provekit/templates/flows/healthcare-intake-redact-summarize.yaml +59 -0
  257. provekit/templates/flows/healthcare-intake-score-gate.yaml +73 -0
  258. provekit/templates/flows/healthcare-intake-sentiment-route.yaml +73 -0
  259. provekit/templates/flows/healthcare-intake-severity-tiers.yaml +103 -0
  260. provekit/templates/flows/healthcare-intake-summarize-then-decide.yaml +88 -0
  261. provekit/templates/flows/healthcare-intake-tag-enrich.yaml +43 -0
  262. provekit/templates/flows/healthcare-intake-tone-rewrite.yaml +43 -0
  263. provekit/templates/flows/healthcare-intake-translate-reply.yaml +58 -0
  264. provekit/templates/flows/healthcare-intake-triage-route.yaml +73 -0
  265. provekit/templates/flows/hr-action-items.yaml +43 -0
  266. provekit/templates/flows/hr-answer.yaml +43 -0
  267. provekit/templates/flows/hr-classify-intent.yaml +43 -0
  268. provekit/templates/flows/hr-draft-critique-revise.yaml +75 -0
  269. provekit/templates/flows/hr-extract-to-json.yaml +43 -0
  270. provekit/templates/flows/hr-faq-match-answer.yaml +60 -0
  271. provekit/templates/flows/hr-keyword-extract.yaml +43 -0
  272. provekit/templates/flows/hr-language-route.yaml +103 -0
  273. provekit/templates/flows/hr-moderation-gate.yaml +73 -0
  274. provekit/templates/flows/hr-redact-summarize.yaml +59 -0
  275. provekit/templates/flows/hr-score-gate.yaml +73 -0
  276. provekit/templates/flows/hr-sentiment-route.yaml +73 -0
  277. provekit/templates/flows/hr-severity-tiers.yaml +103 -0
  278. provekit/templates/flows/hr-summarize-then-decide.yaml +88 -0
  279. provekit/templates/flows/hr-tag-enrich.yaml +43 -0
  280. provekit/templates/flows/hr-tone-rewrite.yaml +43 -0
  281. provekit/templates/flows/hr-translate-reply.yaml +58 -0
  282. provekit/templates/flows/hr-triage-route.yaml +73 -0
  283. provekit/templates/flows/insurance-action-items.yaml +43 -0
  284. provekit/templates/flows/insurance-answer.yaml +43 -0
  285. provekit/templates/flows/insurance-classify-intent.yaml +43 -0
  286. provekit/templates/flows/insurance-draft-critique-revise.yaml +75 -0
  287. provekit/templates/flows/insurance-extract-to-json.yaml +43 -0
  288. provekit/templates/flows/insurance-faq-match-answer.yaml +60 -0
  289. provekit/templates/flows/insurance-keyword-extract.yaml +43 -0
  290. provekit/templates/flows/insurance-language-route.yaml +103 -0
  291. provekit/templates/flows/insurance-moderation-gate.yaml +73 -0
  292. provekit/templates/flows/insurance-redact-summarize.yaml +59 -0
  293. provekit/templates/flows/insurance-score-gate.yaml +73 -0
  294. provekit/templates/flows/insurance-sentiment-route.yaml +73 -0
  295. provekit/templates/flows/insurance-severity-tiers.yaml +103 -0
  296. provekit/templates/flows/insurance-summarize-then-decide.yaml +88 -0
  297. provekit/templates/flows/insurance-tag-enrich.yaml +43 -0
  298. provekit/templates/flows/insurance-tone-rewrite.yaml +43 -0
  299. provekit/templates/flows/insurance-translate-reply.yaml +58 -0
  300. provekit/templates/flows/insurance-triage-route.yaml +73 -0
  301. provekit/templates/flows/it-helpdesk-action-items.yaml +43 -0
  302. provekit/templates/flows/it-helpdesk-answer.yaml +43 -0
  303. provekit/templates/flows/it-helpdesk-classify-intent.yaml +43 -0
  304. provekit/templates/flows/it-helpdesk-draft-critique-revise.yaml +75 -0
  305. provekit/templates/flows/it-helpdesk-extract-to-json.yaml +43 -0
  306. provekit/templates/flows/it-helpdesk-faq-match-answer.yaml +60 -0
  307. provekit/templates/flows/it-helpdesk-keyword-extract.yaml +43 -0
  308. provekit/templates/flows/it-helpdesk-language-route.yaml +103 -0
  309. provekit/templates/flows/it-helpdesk-moderation-gate.yaml +73 -0
  310. provekit/templates/flows/it-helpdesk-redact-summarize.yaml +59 -0
  311. provekit/templates/flows/it-helpdesk-score-gate.yaml +73 -0
  312. provekit/templates/flows/it-helpdesk-sentiment-route.yaml +73 -0
  313. provekit/templates/flows/it-helpdesk-severity-tiers.yaml +103 -0
  314. provekit/templates/flows/it-helpdesk-summarize-then-decide.yaml +88 -0
  315. provekit/templates/flows/it-helpdesk-tag-enrich.yaml +43 -0
  316. provekit/templates/flows/it-helpdesk-tone-rewrite.yaml +43 -0
  317. provekit/templates/flows/it-helpdesk-translate-reply.yaml +58 -0
  318. provekit/templates/flows/it-helpdesk-triage-route.yaml +73 -0
  319. provekit/templates/flows/legal-intake-action-items.yaml +43 -0
  320. provekit/templates/flows/legal-intake-answer.yaml +43 -0
  321. provekit/templates/flows/legal-intake-classify-intent.yaml +43 -0
  322. provekit/templates/flows/legal-intake-draft-critique-revise.yaml +75 -0
  323. provekit/templates/flows/legal-intake-extract-to-json.yaml +43 -0
  324. provekit/templates/flows/legal-intake-faq-match-answer.yaml +60 -0
  325. provekit/templates/flows/legal-intake-keyword-extract.yaml +43 -0
  326. provekit/templates/flows/legal-intake-language-route.yaml +103 -0
  327. provekit/templates/flows/legal-intake-moderation-gate.yaml +73 -0
  328. provekit/templates/flows/legal-intake-redact-summarize.yaml +59 -0
  329. provekit/templates/flows/legal-intake-score-gate.yaml +73 -0
  330. provekit/templates/flows/legal-intake-sentiment-route.yaml +73 -0
  331. provekit/templates/flows/legal-intake-severity-tiers.yaml +103 -0
  332. provekit/templates/flows/legal-intake-summarize-then-decide.yaml +88 -0
  333. provekit/templates/flows/legal-intake-tag-enrich.yaml +43 -0
  334. provekit/templates/flows/legal-intake-tone-rewrite.yaml +43 -0
  335. provekit/templates/flows/legal-intake-translate-reply.yaml +58 -0
  336. provekit/templates/flows/legal-intake-triage-route.yaml +73 -0
  337. provekit/templates/flows/logistics-action-items.yaml +43 -0
  338. provekit/templates/flows/logistics-answer.yaml +43 -0
  339. provekit/templates/flows/logistics-classify-intent.yaml +43 -0
  340. provekit/templates/flows/logistics-draft-critique-revise.yaml +75 -0
  341. provekit/templates/flows/logistics-extract-to-json.yaml +43 -0
  342. provekit/templates/flows/logistics-faq-match-answer.yaml +60 -0
  343. provekit/templates/flows/logistics-keyword-extract.yaml +43 -0
  344. provekit/templates/flows/logistics-language-route.yaml +103 -0
  345. provekit/templates/flows/logistics-moderation-gate.yaml +73 -0
  346. provekit/templates/flows/logistics-redact-summarize.yaml +59 -0
  347. provekit/templates/flows/logistics-score-gate.yaml +73 -0
  348. provekit/templates/flows/logistics-sentiment-route.yaml +73 -0
  349. provekit/templates/flows/logistics-severity-tiers.yaml +103 -0
  350. provekit/templates/flows/logistics-summarize-then-decide.yaml +88 -0
  351. provekit/templates/flows/logistics-tag-enrich.yaml +43 -0
  352. provekit/templates/flows/logistics-tone-rewrite.yaml +43 -0
  353. provekit/templates/flows/logistics-translate-reply.yaml +58 -0
  354. provekit/templates/flows/logistics-triage-route.yaml +73 -0
  355. provekit/templates/flows/marketing-action-items.yaml +43 -0
  356. provekit/templates/flows/marketing-answer.yaml +43 -0
  357. provekit/templates/flows/marketing-classify-intent.yaml +43 -0
  358. provekit/templates/flows/marketing-draft-critique-revise.yaml +75 -0
  359. provekit/templates/flows/marketing-extract-to-json.yaml +43 -0
  360. provekit/templates/flows/marketing-faq-match-answer.yaml +60 -0
  361. provekit/templates/flows/marketing-keyword-extract.yaml +43 -0
  362. provekit/templates/flows/marketing-language-route.yaml +103 -0
  363. provekit/templates/flows/marketing-moderation-gate.yaml +73 -0
  364. provekit/templates/flows/marketing-redact-summarize.yaml +59 -0
  365. provekit/templates/flows/marketing-score-gate.yaml +73 -0
  366. provekit/templates/flows/marketing-sentiment-route.yaml +73 -0
  367. provekit/templates/flows/marketing-severity-tiers.yaml +103 -0
  368. provekit/templates/flows/marketing-summarize-then-decide.yaml +88 -0
  369. provekit/templates/flows/marketing-tag-enrich.yaml +43 -0
  370. provekit/templates/flows/marketing-tone-rewrite.yaml +43 -0
  371. provekit/templates/flows/marketing-translate-reply.yaml +58 -0
  372. provekit/templates/flows/marketing-triage-route.yaml +73 -0
  373. provekit/templates/flows/nonprofit-action-items.yaml +43 -0
  374. provekit/templates/flows/nonprofit-answer.yaml +43 -0
  375. provekit/templates/flows/nonprofit-classify-intent.yaml +43 -0
  376. provekit/templates/flows/nonprofit-draft-critique-revise.yaml +75 -0
  377. provekit/templates/flows/nonprofit-extract-to-json.yaml +43 -0
  378. provekit/templates/flows/nonprofit-faq-match-answer.yaml +60 -0
  379. provekit/templates/flows/nonprofit-keyword-extract.yaml +43 -0
  380. provekit/templates/flows/nonprofit-language-route.yaml +103 -0
  381. provekit/templates/flows/nonprofit-moderation-gate.yaml +73 -0
  382. provekit/templates/flows/nonprofit-redact-summarize.yaml +59 -0
  383. provekit/templates/flows/nonprofit-score-gate.yaml +73 -0
  384. provekit/templates/flows/nonprofit-sentiment-route.yaml +73 -0
  385. provekit/templates/flows/nonprofit-severity-tiers.yaml +103 -0
  386. provekit/templates/flows/nonprofit-summarize-then-decide.yaml +88 -0
  387. provekit/templates/flows/nonprofit-tag-enrich.yaml +43 -0
  388. provekit/templates/flows/nonprofit-tone-rewrite.yaml +43 -0
  389. provekit/templates/flows/nonprofit-translate-reply.yaml +58 -0
  390. provekit/templates/flows/nonprofit-triage-route.yaml +73 -0
  391. provekit/templates/flows/real-estate-action-items.yaml +43 -0
  392. provekit/templates/flows/real-estate-answer.yaml +43 -0
  393. provekit/templates/flows/real-estate-classify-intent.yaml +43 -0
  394. provekit/templates/flows/real-estate-draft-critique-revise.yaml +75 -0
  395. provekit/templates/flows/real-estate-extract-to-json.yaml +43 -0
  396. provekit/templates/flows/real-estate-faq-match-answer.yaml +60 -0
  397. provekit/templates/flows/real-estate-keyword-extract.yaml +43 -0
  398. provekit/templates/flows/real-estate-language-route.yaml +103 -0
  399. provekit/templates/flows/real-estate-moderation-gate.yaml +73 -0
  400. provekit/templates/flows/real-estate-redact-summarize.yaml +59 -0
  401. provekit/templates/flows/real-estate-score-gate.yaml +73 -0
  402. provekit/templates/flows/real-estate-sentiment-route.yaml +73 -0
  403. provekit/templates/flows/real-estate-severity-tiers.yaml +103 -0
  404. provekit/templates/flows/real-estate-summarize-then-decide.yaml +88 -0
  405. provekit/templates/flows/real-estate-tag-enrich.yaml +43 -0
  406. provekit/templates/flows/real-estate-tone-rewrite.yaml +43 -0
  407. provekit/templates/flows/real-estate-translate-reply.yaml +58 -0
  408. provekit/templates/flows/real-estate-triage-route.yaml +73 -0
  409. provekit/templates/flows/recruiting-action-items.yaml +43 -0
  410. provekit/templates/flows/recruiting-answer.yaml +43 -0
  411. provekit/templates/flows/recruiting-classify-intent.yaml +43 -0
  412. provekit/templates/flows/recruiting-draft-critique-revise.yaml +75 -0
  413. provekit/templates/flows/recruiting-extract-to-json.yaml +43 -0
  414. provekit/templates/flows/recruiting-faq-match-answer.yaml +60 -0
  415. provekit/templates/flows/recruiting-keyword-extract.yaml +43 -0
  416. provekit/templates/flows/recruiting-language-route.yaml +103 -0
  417. provekit/templates/flows/recruiting-moderation-gate.yaml +73 -0
  418. provekit/templates/flows/recruiting-redact-summarize.yaml +59 -0
  419. provekit/templates/flows/recruiting-score-gate.yaml +73 -0
  420. provekit/templates/flows/recruiting-sentiment-route.yaml +73 -0
  421. provekit/templates/flows/recruiting-severity-tiers.yaml +103 -0
  422. provekit/templates/flows/recruiting-summarize-then-decide.yaml +88 -0
  423. provekit/templates/flows/recruiting-tag-enrich.yaml +43 -0
  424. provekit/templates/flows/recruiting-tone-rewrite.yaml +43 -0
  425. provekit/templates/flows/recruiting-translate-reply.yaml +58 -0
  426. provekit/templates/flows/recruiting-triage-route.yaml +73 -0
  427. provekit/templates/flows/research-action-items.yaml +43 -0
  428. provekit/templates/flows/research-answer.yaml +43 -0
  429. provekit/templates/flows/research-classify-intent.yaml +43 -0
  430. provekit/templates/flows/research-draft-critique-revise.yaml +75 -0
  431. provekit/templates/flows/research-extract-to-json.yaml +43 -0
  432. provekit/templates/flows/research-faq-match-answer.yaml +60 -0
  433. provekit/templates/flows/research-keyword-extract.yaml +43 -0
  434. provekit/templates/flows/research-language-route.yaml +103 -0
  435. provekit/templates/flows/research-moderation-gate.yaml +73 -0
  436. provekit/templates/flows/research-redact-summarize.yaml +59 -0
  437. provekit/templates/flows/research-score-gate.yaml +73 -0
  438. provekit/templates/flows/research-sentiment-route.yaml +73 -0
  439. provekit/templates/flows/research-severity-tiers.yaml +103 -0
  440. provekit/templates/flows/research-summarize-then-decide.yaml +88 -0
  441. provekit/templates/flows/research-tag-enrich.yaml +43 -0
  442. provekit/templates/flows/research-tone-rewrite.yaml +43 -0
  443. provekit/templates/flows/research-translate-reply.yaml +58 -0
  444. provekit/templates/flows/research-triage-route.yaml +73 -0
  445. provekit/templates/flows/sales-lead-action-items.yaml +43 -0
  446. provekit/templates/flows/sales-lead-answer.yaml +43 -0
  447. provekit/templates/flows/sales-lead-classify-intent.yaml +43 -0
  448. provekit/templates/flows/sales-lead-draft-critique-revise.yaml +75 -0
  449. provekit/templates/flows/sales-lead-extract-to-json.yaml +43 -0
  450. provekit/templates/flows/sales-lead-faq-match-answer.yaml +60 -0
  451. provekit/templates/flows/sales-lead-keyword-extract.yaml +43 -0
  452. provekit/templates/flows/sales-lead-language-route.yaml +103 -0
  453. provekit/templates/flows/sales-lead-moderation-gate.yaml +73 -0
  454. provekit/templates/flows/sales-lead-redact-summarize.yaml +59 -0
  455. provekit/templates/flows/sales-lead-score-gate.yaml +73 -0
  456. provekit/templates/flows/sales-lead-sentiment-route.yaml +73 -0
  457. provekit/templates/flows/sales-lead-severity-tiers.yaml +103 -0
  458. provekit/templates/flows/sales-lead-summarize-then-decide.yaml +88 -0
  459. provekit/templates/flows/sales-lead-tag-enrich.yaml +43 -0
  460. provekit/templates/flows/sales-lead-tone-rewrite.yaml +43 -0
  461. provekit/templates/flows/sales-lead-translate-reply.yaml +58 -0
  462. provekit/templates/flows/sales-lead-triage-route.yaml +73 -0
  463. provekit/templates/flows/travel-action-items.yaml +43 -0
  464. provekit/templates/flows/travel-answer.yaml +43 -0
  465. provekit/templates/flows/travel-classify-intent.yaml +43 -0
  466. provekit/templates/flows/travel-draft-critique-revise.yaml +75 -0
  467. provekit/templates/flows/travel-extract-to-json.yaml +43 -0
  468. provekit/templates/flows/travel-faq-match-answer.yaml +60 -0
  469. provekit/templates/flows/travel-keyword-extract.yaml +43 -0
  470. provekit/templates/flows/travel-language-route.yaml +103 -0
  471. provekit/templates/flows/travel-moderation-gate.yaml +73 -0
  472. provekit/templates/flows/travel-redact-summarize.yaml +59 -0
  473. provekit/templates/flows/travel-score-gate.yaml +73 -0
  474. provekit/templates/flows/travel-sentiment-route.yaml +73 -0
  475. provekit/templates/flows/travel-severity-tiers.yaml +103 -0
  476. provekit/templates/flows/travel-summarize-then-decide.yaml +88 -0
  477. provekit/templates/flows/travel-tag-enrich.yaml +43 -0
  478. provekit/templates/flows/travel-tone-rewrite.yaml +43 -0
  479. provekit/templates/flows/travel-translate-reply.yaml +58 -0
  480. provekit/templates/flows/travel-triage-route.yaml +73 -0
  481. provekit-0.1.0.dist-info/METADATA +86 -0
  482. provekit-0.1.0.dist-info/RECORD +485 -0
  483. provekit-0.1.0.dist-info/WHEEL +5 -0
  484. provekit-0.1.0.dist-info/entry_points.txt +2 -0
  485. provekit-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,241 @@
1
+ """baseline schema
2
+
3
+ Revision ID: 49e8ab812556
4
+ Revises:
5
+ Create Date: 2026-07-16 23:49:32.276669
6
+ """
7
+ from alembic import op
8
+ import sqlalchemy as sa
9
+ import provekit.models
10
+
11
+
12
+ revision = '49e8ab812556'
13
+ down_revision = None
14
+ branch_labels = None
15
+ depends_on = None
16
+
17
+
18
+ def upgrade() -> None:
19
+ # ### commands auto generated by Alembic - please adjust! ###
20
+ op.create_table('users',
21
+ sa.Column('id', sa.Integer(), nullable=False),
22
+ sa.Column('email', sa.String(length=255), nullable=False),
23
+ sa.Column('name', sa.String(length=160), nullable=False),
24
+ sa.Column('password_hash', sa.String(length=255), nullable=False),
25
+ sa.Column('auth_provider', sa.String(length=32), nullable=False),
26
+ sa.Column('created_at', sa.DateTime(), nullable=False),
27
+ sa.PrimaryKeyConstraint('id', name=op.f('pk_users')),
28
+ sa.UniqueConstraint('email', name=op.f('uq_users_email'))
29
+ )
30
+ op.create_table('workspaces',
31
+ sa.Column('id', sa.Integer(), nullable=False),
32
+ sa.Column('name', sa.String(length=160), nullable=False),
33
+ sa.Column('owner_user_id', sa.Integer(), nullable=False),
34
+ sa.Column('created_at', sa.DateTime(), nullable=False),
35
+ sa.ForeignKeyConstraint(['owner_user_id'], ['users.id'], name=op.f('fk_workspaces_owner_user_id_users')),
36
+ sa.PrimaryKeyConstraint('id', name=op.f('pk_workspaces'))
37
+ )
38
+ with op.batch_alter_table('workspaces', schema=None) as batch_op:
39
+ batch_op.create_index(batch_op.f('ix_workspaces_owner_user_id'), ['owner_user_id'], unique=False)
40
+
41
+ op.create_table('collections',
42
+ sa.Column('id', sa.Integer(), nullable=False),
43
+ sa.Column('workspace_id', sa.Integer(), nullable=True),
44
+ sa.Column('name', sa.String(length=120), nullable=False),
45
+ sa.Column('created_at', sa.DateTime(), nullable=False),
46
+ sa.ForeignKeyConstraint(['workspace_id'], ['workspaces.id'], name=op.f('fk_collections_workspace_id_workspaces')),
47
+ sa.PrimaryKeyConstraint('id', name=op.f('pk_collections'))
48
+ )
49
+ with op.batch_alter_table('collections', schema=None) as batch_op:
50
+ batch_op.create_index(batch_op.f('ix_collections_workspace_id'), ['workspace_id'], unique=False)
51
+
52
+ op.create_table('connections',
53
+ sa.Column('id', sa.Integer(), nullable=False),
54
+ sa.Column('workspace_id', sa.Integer(), nullable=True),
55
+ sa.Column('name', sa.String(length=120), nullable=False),
56
+ sa.Column('kind', sa.String(length=16), nullable=False),
57
+ sa.Column('config', provekit.models.SealedJSON(), nullable=False),
58
+ sa.Column('created_at', sa.DateTime(), nullable=False),
59
+ sa.ForeignKeyConstraint(['workspace_id'], ['workspaces.id'], name=op.f('fk_connections_workspace_id_workspaces')),
60
+ sa.PrimaryKeyConstraint('id', name=op.f('pk_connections'))
61
+ )
62
+ with op.batch_alter_table('connections', schema=None) as batch_op:
63
+ batch_op.create_index(batch_op.f('ix_connections_workspace_id'), ['workspace_id'], unique=False)
64
+
65
+ op.create_table('datasets',
66
+ sa.Column('id', sa.Integer(), nullable=False),
67
+ sa.Column('workspace_id', sa.Integer(), nullable=True),
68
+ sa.Column('name', sa.String(length=160), nullable=False),
69
+ sa.Column('rows', sa.JSON(), nullable=False),
70
+ sa.Column('created_at', sa.DateTime(), nullable=False),
71
+ sa.ForeignKeyConstraint(['workspace_id'], ['workspaces.id'], name=op.f('fk_datasets_workspace_id_workspaces')),
72
+ sa.PrimaryKeyConstraint('id', name=op.f('pk_datasets'))
73
+ )
74
+ with op.batch_alter_table('datasets', schema=None) as batch_op:
75
+ batch_op.create_index(batch_op.f('ix_datasets_workspace_id'), ['workspace_id'], unique=False)
76
+
77
+ op.create_table('environments',
78
+ sa.Column('id', sa.Integer(), nullable=False),
79
+ sa.Column('workspace_id', sa.Integer(), nullable=True),
80
+ sa.Column('name', sa.String(length=120), nullable=False),
81
+ sa.Column('variables', sa.JSON(), nullable=False),
82
+ sa.Column('is_active', sa.Boolean(), nullable=False),
83
+ sa.ForeignKeyConstraint(['workspace_id'], ['workspaces.id'], name=op.f('fk_environments_workspace_id_workspaces')),
84
+ sa.PrimaryKeyConstraint('id', name=op.f('pk_environments'))
85
+ )
86
+ with op.batch_alter_table('environments', schema=None) as batch_op:
87
+ batch_op.create_index(batch_op.f('ix_environments_workspace_id'), ['workspace_id'], unique=False)
88
+
89
+ op.create_table('flows',
90
+ sa.Column('id', sa.Integer(), nullable=False),
91
+ sa.Column('workspace_id', sa.Integer(), nullable=True),
92
+ sa.Column('name', sa.String(length=160), nullable=False),
93
+ sa.Column('description', sa.Text(), nullable=False),
94
+ sa.Column('nodes', sa.JSON(), nullable=False),
95
+ sa.Column('edges', sa.JSON(), nullable=False),
96
+ sa.Column('updated_at', sa.DateTime(), nullable=False),
97
+ sa.ForeignKeyConstraint(['workspace_id'], ['workspaces.id'], name=op.f('fk_flows_workspace_id_workspaces')),
98
+ sa.PrimaryKeyConstraint('id', name=op.f('pk_flows'))
99
+ )
100
+ with op.batch_alter_table('flows', schema=None) as batch_op:
101
+ batch_op.create_index(batch_op.f('ix_flows_workspace_id'), ['workspace_id'], unique=False)
102
+
103
+ op.create_table('prompts',
104
+ sa.Column('id', sa.Integer(), nullable=False),
105
+ sa.Column('workspace_id', sa.Integer(), nullable=True),
106
+ sa.Column('key', sa.String(length=80), nullable=False),
107
+ sa.Column('name', sa.String(length=160), nullable=False),
108
+ sa.Column('description', sa.Text(), nullable=False),
109
+ sa.Column('content', sa.Text(), nullable=False),
110
+ sa.Column('updated_at', sa.DateTime(), nullable=False),
111
+ sa.ForeignKeyConstraint(['workspace_id'], ['workspaces.id'], name=op.f('fk_prompts_workspace_id_workspaces')),
112
+ sa.PrimaryKeyConstraint('id', name=op.f('pk_prompts')),
113
+ sa.UniqueConstraint('workspace_id', 'key', name='uq_prompt_key')
114
+ )
115
+ with op.batch_alter_table('prompts', schema=None) as batch_op:
116
+ batch_op.create_index(batch_op.f('ix_prompts_workspace_id'), ['workspace_id'], unique=False)
117
+
118
+ op.create_table('workspace_members',
119
+ sa.Column('id', sa.Integer(), nullable=False),
120
+ sa.Column('workspace_id', sa.Integer(), nullable=False),
121
+ sa.Column('user_id', sa.Integer(), nullable=False),
122
+ sa.Column('role', sa.String(length=16), nullable=False),
123
+ sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_workspace_members_user_id_users')),
124
+ sa.ForeignKeyConstraint(['workspace_id'], ['workspaces.id'], name=op.f('fk_workspace_members_workspace_id_workspaces')),
125
+ sa.PrimaryKeyConstraint('id', name=op.f('pk_workspace_members')),
126
+ sa.UniqueConstraint('workspace_id', 'user_id', name='uq_member')
127
+ )
128
+ with op.batch_alter_table('workspace_members', schema=None) as batch_op:
129
+ batch_op.create_index(batch_op.f('ix_workspace_members_user_id'), ['user_id'], unique=False)
130
+ batch_op.create_index(batch_op.f('ix_workspace_members_workspace_id'), ['workspace_id'], unique=False)
131
+
132
+ op.create_table('deployments',
133
+ sa.Column('id', sa.Integer(), nullable=False),
134
+ sa.Column('workspace_id', sa.Integer(), nullable=True),
135
+ sa.Column('flow_id', sa.Integer(), nullable=True),
136
+ sa.Column('slug', sa.String(length=80), nullable=False),
137
+ sa.Column('version', sa.Integer(), nullable=False),
138
+ sa.Column('name', sa.String(length=160), nullable=False),
139
+ sa.Column('snapshot', sa.JSON(), nullable=False),
140
+ sa.Column('api_key_hash', sa.String(length=128), nullable=False),
141
+ sa.Column('active', sa.Boolean(), nullable=False),
142
+ sa.Column('created_at', sa.DateTime(), nullable=False),
143
+ sa.ForeignKeyConstraint(['flow_id'], ['flows.id'], name=op.f('fk_deployments_flow_id_flows')),
144
+ sa.ForeignKeyConstraint(['workspace_id'], ['workspaces.id'], name=op.f('fk_deployments_workspace_id_workspaces')),
145
+ sa.PrimaryKeyConstraint('id', name=op.f('pk_deployments'))
146
+ )
147
+ with op.batch_alter_table('deployments', schema=None) as batch_op:
148
+ batch_op.create_index(batch_op.f('ix_deployments_active'), ['active'], unique=False)
149
+ batch_op.create_index(batch_op.f('ix_deployments_slug'), ['slug'], unique=False)
150
+ batch_op.create_index(batch_op.f('ix_deployments_workspace_id'), ['workspace_id'], unique=False)
151
+
152
+ op.create_table('requests',
153
+ sa.Column('id', sa.Integer(), nullable=False),
154
+ sa.Column('workspace_id', sa.Integer(), nullable=True),
155
+ sa.Column('collection_id', sa.Integer(), nullable=True),
156
+ sa.Column('name', sa.String(length=160), nullable=False),
157
+ sa.Column('type', sa.String(length=16), nullable=False),
158
+ sa.Column('payload', sa.JSON(), nullable=False),
159
+ sa.Column('updated_at', sa.DateTime(), nullable=False),
160
+ sa.ForeignKeyConstraint(['collection_id'], ['collections.id'], name=op.f('fk_requests_collection_id_collections')),
161
+ sa.ForeignKeyConstraint(['workspace_id'], ['workspaces.id'], name=op.f('fk_requests_workspace_id_workspaces')),
162
+ sa.PrimaryKeyConstraint('id', name=op.f('pk_requests'))
163
+ )
164
+ with op.batch_alter_table('requests', schema=None) as batch_op:
165
+ batch_op.create_index(batch_op.f('ix_requests_workspace_id'), ['workspace_id'], unique=False)
166
+
167
+ op.create_table('runs',
168
+ sa.Column('id', sa.Integer(), nullable=False),
169
+ sa.Column('workspace_id', sa.Integer(), nullable=True),
170
+ sa.Column('deployment_id', sa.Integer(), nullable=True),
171
+ sa.Column('type', sa.String(length=16), nullable=False),
172
+ sa.Column('label', sa.String(length=200), nullable=False),
173
+ sa.Column('request', sa.JSON(), nullable=False),
174
+ sa.Column('result', sa.JSON(), nullable=False),
175
+ sa.Column('status', sa.String(length=16), nullable=False),
176
+ sa.Column('duration_ms', sa.Integer(), nullable=False),
177
+ sa.Column('error', sa.Text(), nullable=False),
178
+ sa.Column('created_at', sa.DateTime(), nullable=False),
179
+ sa.ForeignKeyConstraint(['deployment_id'], ['deployments.id'], name=op.f('fk_runs_deployment_id_deployments')),
180
+ sa.ForeignKeyConstraint(['workspace_id'], ['workspaces.id'], name=op.f('fk_runs_workspace_id_workspaces')),
181
+ sa.PrimaryKeyConstraint('id', name=op.f('pk_runs'))
182
+ )
183
+ with op.batch_alter_table('runs', schema=None) as batch_op:
184
+ batch_op.create_index(batch_op.f('ix_runs_deployment_id'), ['deployment_id'], unique=False)
185
+ batch_op.create_index(batch_op.f('ix_runs_workspace_id'), ['workspace_id'], unique=False)
186
+
187
+ # ### end Alembic commands ###
188
+
189
+
190
+ def downgrade() -> None:
191
+ # ### commands auto generated by Alembic - please adjust! ###
192
+ with op.batch_alter_table('runs', schema=None) as batch_op:
193
+ batch_op.drop_index(batch_op.f('ix_runs_workspace_id'))
194
+ batch_op.drop_index(batch_op.f('ix_runs_deployment_id'))
195
+
196
+ op.drop_table('runs')
197
+ with op.batch_alter_table('requests', schema=None) as batch_op:
198
+ batch_op.drop_index(batch_op.f('ix_requests_workspace_id'))
199
+
200
+ op.drop_table('requests')
201
+ with op.batch_alter_table('deployments', schema=None) as batch_op:
202
+ batch_op.drop_index(batch_op.f('ix_deployments_workspace_id'))
203
+ batch_op.drop_index(batch_op.f('ix_deployments_slug'))
204
+ batch_op.drop_index(batch_op.f('ix_deployments_active'))
205
+
206
+ op.drop_table('deployments')
207
+ with op.batch_alter_table('workspace_members', schema=None) as batch_op:
208
+ batch_op.drop_index(batch_op.f('ix_workspace_members_workspace_id'))
209
+ batch_op.drop_index(batch_op.f('ix_workspace_members_user_id'))
210
+
211
+ op.drop_table('workspace_members')
212
+ with op.batch_alter_table('prompts', schema=None) as batch_op:
213
+ batch_op.drop_index(batch_op.f('ix_prompts_workspace_id'))
214
+
215
+ op.drop_table('prompts')
216
+ with op.batch_alter_table('flows', schema=None) as batch_op:
217
+ batch_op.drop_index(batch_op.f('ix_flows_workspace_id'))
218
+
219
+ op.drop_table('flows')
220
+ with op.batch_alter_table('environments', schema=None) as batch_op:
221
+ batch_op.drop_index(batch_op.f('ix_environments_workspace_id'))
222
+
223
+ op.drop_table('environments')
224
+ with op.batch_alter_table('datasets', schema=None) as batch_op:
225
+ batch_op.drop_index(batch_op.f('ix_datasets_workspace_id'))
226
+
227
+ op.drop_table('datasets')
228
+ with op.batch_alter_table('connections', schema=None) as batch_op:
229
+ batch_op.drop_index(batch_op.f('ix_connections_workspace_id'))
230
+
231
+ op.drop_table('connections')
232
+ with op.batch_alter_table('collections', schema=None) as batch_op:
233
+ batch_op.drop_index(batch_op.f('ix_collections_workspace_id'))
234
+
235
+ op.drop_table('collections')
236
+ with op.batch_alter_table('workspaces', schema=None) as batch_op:
237
+ batch_op.drop_index(batch_op.f('ix_workspaces_owner_user_id'))
238
+
239
+ op.drop_table('workspaces')
240
+ op.drop_table('users')
241
+ # ### end Alembic commands ###
@@ -0,0 +1,35 @@
1
+ """workspace ingest key
2
+
3
+ Revision ID: 819ed5ff183e
4
+ Revises: 49e8ab812556
5
+ Create Date: 2026-07-17 00:25:59.721254
6
+ """
7
+ from alembic import op
8
+ import sqlalchemy as sa
9
+
10
+
11
+ revision = '819ed5ff183e'
12
+ down_revision = '49e8ab812556'
13
+ branch_labels = None
14
+ depends_on = None
15
+
16
+
17
+ def upgrade() -> None:
18
+ # ### commands auto generated by Alembic - please adjust! ###
19
+ with op.batch_alter_table('workspaces', schema=None) as batch_op:
20
+ # server_default="" so adding this NOT NULL column succeeds on databases that
21
+ # already have workspace rows (otherwise the ALTER fails at upgrade time).
22
+ batch_op.add_column(sa.Column('ingest_key_hash', sa.String(length=128), nullable=False,
23
+ server_default=''))
24
+ batch_op.create_index(batch_op.f('ix_workspaces_ingest_key_hash'), ['ingest_key_hash'], unique=False)
25
+
26
+ # ### end Alembic commands ###
27
+
28
+
29
+ def downgrade() -> None:
30
+ # ### commands auto generated by Alembic - please adjust! ###
31
+ with op.batch_alter_table('workspaces', schema=None) as batch_op:
32
+ batch_op.drop_index(batch_op.f('ix_workspaces_ingest_key_hash'))
33
+ batch_op.drop_column('ingest_key_hash')
34
+
35
+ # ### end Alembic commands ###
@@ -0,0 +1,27 @@
1
+ """user token_version
2
+
3
+ Revision ID: a1b2c3d4e5f6
4
+ Revises: 323eb73d463c
5
+ Create Date: 2026-07-17 06:10:00.000000
6
+ """
7
+ from alembic import op
8
+ import sqlalchemy as sa
9
+
10
+
11
+ revision = 'a1b2c3d4e5f6'
12
+ down_revision = '323eb73d463c'
13
+ branch_labels = None
14
+ depends_on = None
15
+
16
+
17
+ def upgrade() -> None:
18
+ with op.batch_alter_table('users', schema=None) as batch_op:
19
+ # server_default="0" so the NOT NULL column populates on existing rows; all current
20
+ # sessions carry v=0 (or no v, read as 0) and stay valid until the next reset.
21
+ batch_op.add_column(sa.Column('token_version', sa.Integer(), nullable=False,
22
+ server_default='0'))
23
+
24
+
25
+ def downgrade() -> None:
26
+ with op.batch_alter_table('users', schema=None) as batch_op:
27
+ batch_op.drop_column('token_version')
provekit/models.py ADDED
@@ -0,0 +1,191 @@
1
+ """ProveKit data model. Everything the console persists: connections (providers),
2
+ collections + saved requests, environments (variables), and run history."""
3
+ from datetime import datetime, timezone
4
+
5
+ from sqlalchemy import JSON, DateTime, ForeignKey, Integer, String, Text, TypeDecorator, UniqueConstraint
6
+ from sqlalchemy.orm import Mapped, mapped_column
7
+
8
+ from .database import Base
9
+
10
+
11
+ def _ws_fk() -> Mapped[int]:
12
+ """Workspace FK shared by every tenant-scoped table (indexed for per-workspace queries)."""
13
+ return mapped_column(ForeignKey("workspaces.id"), index=True, nullable=True)
14
+
15
+
16
+ def _now() -> datetime:
17
+ return datetime.now(timezone.utc)
18
+
19
+
20
+ def iso_utc(dt: datetime | None) -> str | None:
21
+ """Serialize a stored timestamp as ISO-8601 with an explicit UTC offset. Timestamps
22
+ are written in UTC (_now), but SQLite hands them back naive — without the offset the
23
+ browser would parse them as local time."""
24
+ if dt is None:
25
+ return None
26
+ if dt.tzinfo is None:
27
+ dt = dt.replace(tzinfo=timezone.utc)
28
+ return dt.isoformat()
29
+
30
+
31
+ class SealedJSON(TypeDecorator):
32
+ """JSON column whose secret fields (api_key, auth headers) are encrypted at rest.
33
+ Application code always sees plaintext; the database file never does."""
34
+ impl = JSON
35
+ cache_ok = True
36
+
37
+ def process_bind_param(self, value, dialect):
38
+ from .services.sealing import seal_config
39
+ return seal_config(value) if isinstance(value, dict) else value
40
+
41
+ def process_result_value(self, value, dialect):
42
+ from .services.sealing import unseal_config
43
+ return unseal_config(value) if isinstance(value, dict) else value
44
+
45
+
46
+ class User(Base):
47
+ """An account. password_hash is null for OAuth-only users."""
48
+ __tablename__ = "users"
49
+ id: Mapped[int] = mapped_column(primary_key=True)
50
+ email: Mapped[str] = mapped_column(String(255), unique=True)
51
+ name: Mapped[str] = mapped_column(String(160), default="")
52
+ password_hash: Mapped[str] = mapped_column(String(255), default="")
53
+ auth_provider: Mapped[str] = mapped_column(String(32), default="password") # password | github | local
54
+ email_verified: Mapped[bool] = mapped_column(default=False)
55
+ # Bumped on password reset to revoke every previously-issued token (sessions + the
56
+ # just-used reset link): tokens embed the version and are rejected once it moves on.
57
+ token_version: Mapped[int] = mapped_column(default=0)
58
+ created_at: Mapped[datetime] = mapped_column(DateTime, default=_now)
59
+
60
+
61
+ class Workspace(Base):
62
+ """A tenant boundary. Every user gets a default workspace; teams share one later."""
63
+ __tablename__ = "workspaces"
64
+ id: Mapped[int] = mapped_column(primary_key=True)
65
+ name: Mapped[str] = mapped_column(String(160), default="My workspace")
66
+ owner_user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True)
67
+ # Bearer token for unattended OTLP trace ingest (exporters can't send cookies).
68
+ ingest_key_hash: Mapped[str] = mapped_column(String(128), default="", index=True)
69
+ created_at: Mapped[datetime] = mapped_column(DateTime, default=_now)
70
+
71
+
72
+ class WorkspaceMember(Base):
73
+ __tablename__ = "workspace_members"
74
+ id: Mapped[int] = mapped_column(primary_key=True)
75
+ workspace_id: Mapped[int] = mapped_column(ForeignKey("workspaces.id"), index=True)
76
+ user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True)
77
+ role: Mapped[str] = mapped_column(String(16), default="member") # owner | member
78
+ __table_args__ = (UniqueConstraint("workspace_id", "user_id", name="uq_member"),)
79
+
80
+
81
+ class Connection(Base):
82
+ """A provider you can run against. kind = llm | mcp | agent."""
83
+ __tablename__ = "connections"
84
+ id: Mapped[int] = mapped_column(primary_key=True)
85
+ workspace_id: Mapped[int] = _ws_fk()
86
+ name: Mapped[str] = mapped_column(String(120))
87
+ kind: Mapped[str] = mapped_column(String(16)) # llm | mcp | agent
88
+ # config shape by kind:
89
+ # llm -> {provider: openai|anthropic|compatible, base_url, api_key, models: [str]}
90
+ # mcp -> {url}
91
+ # agent -> {base_url, headers: {}}
92
+ config: Mapped[dict] = mapped_column(SealedJSON, default=dict)
93
+ created_at: Mapped[datetime] = mapped_column(DateTime, default=_now)
94
+
95
+
96
+ class Collection(Base):
97
+ __tablename__ = "collections"
98
+ id: Mapped[int] = mapped_column(primary_key=True)
99
+ workspace_id: Mapped[int] = _ws_fk()
100
+ name: Mapped[str] = mapped_column(String(120))
101
+ created_at: Mapped[datetime] = mapped_column(DateTime, default=_now)
102
+
103
+
104
+ class Request(Base):
105
+ """A saved request. type = prompt | tool | agent. payload holds the type-specific body."""
106
+ __tablename__ = "requests"
107
+ id: Mapped[int] = mapped_column(primary_key=True)
108
+ workspace_id: Mapped[int] = _ws_fk()
109
+ collection_id: Mapped[int | None] = mapped_column(ForeignKey("collections.id"), nullable=True)
110
+ name: Mapped[str] = mapped_column(String(160))
111
+ type: Mapped[str] = mapped_column(String(16))
112
+ payload: Mapped[dict] = mapped_column(JSON, default=dict)
113
+ updated_at: Mapped[datetime] = mapped_column(DateTime, default=_now, onupdate=_now)
114
+
115
+
116
+ class Environment(Base):
117
+ __tablename__ = "environments"
118
+ id: Mapped[int] = mapped_column(primary_key=True)
119
+ workspace_id: Mapped[int] = _ws_fk()
120
+ name: Mapped[str] = mapped_column(String(120))
121
+ variables: Mapped[dict] = mapped_column(JSON, default=dict)
122
+ is_active: Mapped[bool] = mapped_column(default=False)
123
+
124
+
125
+ class Prompt(Base):
126
+ """A managed, reusable prompt (the generic Prompt Registry)."""
127
+ __tablename__ = "prompts"
128
+ id: Mapped[int] = mapped_column(primary_key=True)
129
+ workspace_id: Mapped[int] = _ws_fk()
130
+ key: Mapped[str] = mapped_column(String(80))
131
+ name: Mapped[str] = mapped_column(String(160))
132
+ description: Mapped[str] = mapped_column(Text, default="")
133
+ content: Mapped[str] = mapped_column(Text, default="")
134
+ updated_at: Mapped[datetime] = mapped_column(DateTime, default=_now, onupdate=_now)
135
+ __table_args__ = (UniqueConstraint("workspace_id", "key", name="uq_prompt_key"),)
136
+
137
+
138
+ class Flow(Base):
139
+ """A visual agent workflow: a graph of nodes + edges executed by the flow engine."""
140
+ __tablename__ = "flows"
141
+ id: Mapped[int] = mapped_column(primary_key=True)
142
+ workspace_id: Mapped[int] = _ws_fk()
143
+ name: Mapped[str] = mapped_column(String(160))
144
+ description: Mapped[str] = mapped_column(Text, default="")
145
+ nodes: Mapped[list] = mapped_column(JSON, default=list)
146
+ edges: Mapped[list] = mapped_column(JSON, default=list)
147
+ updated_at: Mapped[datetime] = mapped_column(DateTime, default=_now, onupdate=_now)
148
+
149
+
150
+ class Dataset(Base):
151
+ """A reusable, named set of input rows — run any request over it. rows =
152
+ [{name, variables}]. Decoupled from requests, like a shared data file."""
153
+ __tablename__ = "datasets"
154
+ id: Mapped[int] = mapped_column(primary_key=True)
155
+ workspace_id: Mapped[int] = _ws_fk()
156
+ name: Mapped[str] = mapped_column(String(160))
157
+ rows: Mapped[list] = mapped_column(JSON, default=list)
158
+ created_at: Mapped[datetime] = mapped_column(DateTime, default=_now)
159
+
160
+
161
+ class Deployment(Base):
162
+ """A published flow snapshot, callable as a hosted endpoint. Rows share a `slug`
163
+ across versions; exactly one version per slug is active. The graph is frozen in
164
+ `snapshot` at deploy time so editing the flow never changes production."""
165
+ __tablename__ = "deployments"
166
+ id: Mapped[int] = mapped_column(primary_key=True)
167
+ workspace_id: Mapped[int] = _ws_fk()
168
+ flow_id: Mapped[int | None] = mapped_column(ForeignKey("flows.id"), nullable=True)
169
+ slug: Mapped[str] = mapped_column(String(80), index=True)
170
+ version: Mapped[int] = mapped_column(Integer, default=1)
171
+ name: Mapped[str] = mapped_column(String(160), default="")
172
+ snapshot: Mapped[dict] = mapped_column(JSON, default=dict) # {nodes, edges}
173
+ api_key_hash: Mapped[str] = mapped_column(String(128))
174
+ active: Mapped[bool] = mapped_column(default=True, index=True)
175
+ created_at: Mapped[datetime] = mapped_column(DateTime, default=_now)
176
+
177
+
178
+ class Run(Base):
179
+ """A single execution + its result (for history/replay)."""
180
+ __tablename__ = "runs"
181
+ id: Mapped[int] = mapped_column(primary_key=True)
182
+ workspace_id: Mapped[int] = _ws_fk()
183
+ deployment_id: Mapped[int | None] = mapped_column(ForeignKey("deployments.id"), index=True, nullable=True)
184
+ type: Mapped[str] = mapped_column(String(16))
185
+ label: Mapped[str] = mapped_column(String(200), default="")
186
+ request: Mapped[dict] = mapped_column(JSON, default=dict) # the sent request
187
+ result: Mapped[dict] = mapped_column(JSON, default=dict) # {output, meta, events?}
188
+ status: Mapped[str] = mapped_column(String(16), default="completed")
189
+ duration_ms: Mapped[int] = mapped_column(Integer, default=0)
190
+ error: Mapped[str] = mapped_column(Text, default="")
191
+ created_at: Mapped[datetime] = mapped_column(DateTime, default=_now)
@@ -0,0 +1,154 @@
1
+ """Observability: request IDs, structured JSON logs (hosted), optional Sentry, /healthz.
2
+
3
+ Logs never include prompt/response bodies or secrets — only run lifecycle metadata.
4
+ """
5
+ from __future__ import annotations
6
+
7
+ import json
8
+ import logging
9
+ import uuid
10
+ from contextvars import ContextVar
11
+
12
+ from fastapi import Request
13
+ from fastapi.responses import JSONResponse
14
+ from sqlalchemy import text
15
+ from starlette.middleware.base import BaseHTTPMiddleware
16
+
17
+ from .config import get_settings
18
+ from .database import SessionLocal
19
+
20
+ request_id: ContextVar[str] = ContextVar("request_id", default="-")
21
+
22
+
23
+ class _JSONFormatter(logging.Formatter):
24
+ def format(self, record: logging.LogRecord) -> str:
25
+ payload = {"level": record.levelname, "logger": record.name,
26
+ "msg": record.getMessage(), "request_id": request_id.get()}
27
+ if record.exc_info:
28
+ payload["exc"] = self.formatException(record.exc_info)
29
+ return json.dumps(payload)
30
+
31
+
32
+ def setup_logging() -> None:
33
+ s = get_settings()
34
+ root = logging.getLogger()
35
+ root.setLevel(logging.INFO)
36
+ if s.hosted: # machine-parseable logs in production
37
+ for h in root.handlers:
38
+ h.setFormatter(_JSONFormatter())
39
+
40
+
41
+ def init_sentry() -> None:
42
+ dsn = get_settings().sentry_dsn
43
+ if not dsn:
44
+ return
45
+ try:
46
+ import sentry_sdk
47
+ sentry_sdk.init(dsn=dsn, traces_sample_rate=0.1)
48
+ logging.getLogger("provekit").info("sentry enabled")
49
+ except ImportError:
50
+ logging.getLogger("provekit").warning("SENTRY_DSN set but sentry-sdk not installed")
51
+
52
+
53
+ class RequestIDMiddleware(BaseHTTPMiddleware):
54
+ """Assign/propagate X-Request-ID and bind it to logs for the duration of the request."""
55
+ async def dispatch(self, request: Request, call_next):
56
+ rid = request.headers.get("x-request-id") or uuid.uuid4().hex[:16]
57
+ token = request_id.set(rid)
58
+ try:
59
+ response = await call_next(request)
60
+ finally:
61
+ request_id.reset(token)
62
+ response.headers["X-Request-ID"] = rid
63
+ return response
64
+
65
+
66
+ class SecurityHeadersMiddleware(BaseHTTPMiddleware):
67
+ """Baseline hardening headers on every response; HSTS only in hosted (TLS) mode."""
68
+ async def dispatch(self, request: Request, call_next):
69
+ response = await call_next(request)
70
+ response.headers.setdefault("X-Content-Type-Options", "nosniff")
71
+ response.headers.setdefault("X-Frame-Options", "DENY")
72
+ response.headers.setdefault("Referrer-Policy", "strict-origin-when-cross-origin")
73
+ if get_settings().hosted:
74
+ response.headers.setdefault("Strict-Transport-Security",
75
+ "max-age=31536000; includeSubDomains")
76
+ return response
77
+
78
+
79
+ class BodySizeLimitMiddleware:
80
+ """Reject oversized request bodies with 413. Pure ASGI so the cap holds for chunked /
81
+ Content-Length-less requests too: the body is buffered up to the limit and then replayed
82
+ to the app (this API takes small JSON bodies, so buffering is cheap)."""
83
+ def __init__(self, app):
84
+ self.app = app
85
+
86
+ async def __call__(self, scope, receive, send):
87
+ if scope["type"] != "http":
88
+ return await self.app(scope, receive, send)
89
+ max_bytes = get_settings().max_body_bytes
90
+ headers = dict(scope.get("headers") or [])
91
+ cl = headers.get(b"content-length")
92
+ if cl is not None and cl.isdigit() and int(cl) > max_bytes:
93
+ return await self._reject(send)
94
+ body = bytearray()
95
+ while True:
96
+ message = await receive()
97
+ if message["type"] == "http.disconnect":
98
+ # The client vanished mid-upload. Returning bare would satisfy a pure-ASGI
99
+ # parent, but this runs inside BaseHTTPMiddleware (RequestID/SecurityHeaders),
100
+ # whose call_next raises "No response returned." if nothing is sent — turning
101
+ # every cancelled upload into a 500 + Sentry event. Nobody reads this response.
102
+ return await self._respond(send, 499, "Client disconnected")
103
+ body.extend(message.get("body", b""))
104
+ if len(body) > max_bytes:
105
+ return await self._reject(send)
106
+ if not message.get("more_body", False):
107
+ break
108
+ buffered = bytes(body)
109
+ done = False
110
+
111
+ async def replay():
112
+ nonlocal done
113
+ if not done:
114
+ done = True
115
+ return {"type": "http.request", "body": buffered, "more_body": False}
116
+ # Delegate later reads to the real channel so a StreamingResponse's disconnect
117
+ # listener gets genuine http.disconnect events (returning a fake one truncates SSE).
118
+ return await receive()
119
+
120
+ await self.app(scope, replay, send)
121
+
122
+ @classmethod
123
+ async def _reject(cls, send):
124
+ return await cls._respond(send, 413, "Request body too large")
125
+
126
+ @staticmethod
127
+ async def _respond(send, status: int, detail: str):
128
+ body = json.dumps({"detail": detail}).encode()
129
+ await send({"type": "http.response.start", "status": status,
130
+ "headers": [(b"content-type", b"application/json"),
131
+ (b"content-length", str(len(body)).encode())]})
132
+ await send({"type": "http.response.body", "body": body})
133
+
134
+
135
+ def healthz() -> JSONResponse:
136
+ """Liveness+readiness: DB reachable, and Redis if configured."""
137
+ checks = {"db": False, "redis": None}
138
+ try:
139
+ db = SessionLocal()
140
+ db.execute(text("SELECT 1"))
141
+ db.close()
142
+ checks["db"] = True
143
+ except Exception:
144
+ pass
145
+ if get_settings().redis_url:
146
+ checks["redis"] = False
147
+ try:
148
+ from .services.runstore import _store
149
+ _store()._r.ping()
150
+ checks["redis"] = True
151
+ except Exception:
152
+ pass
153
+ ok = checks["db"] and (checks["redis"] is not False)
154
+ return JSONResponse({"ok": ok, "checks": checks}, status_code=200 if ok else 503)
File without changes