@desplega.ai/agent-swarm 1.129.0 → 1.131.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 (226) hide show
  1. package/README.md +2 -2
  2. package/dist/{actions-kfv2dawe.js → actions-w53mbns9.js} +11 -11
  3. package/dist/{anthropic-messages-3xgme8my.js → anthropic-messages-rjmd2e7n.js} +5 -5
  4. package/dist/{app-q8vjk6e8.js → app-m9gwqsqv.js} +8 -8
  5. package/dist/{artifact-hg4t1nx7.js → artifact-jysj3wrg.js} +2 -2
  6. package/dist/{assistant-g037r345.js → assistant-bp65m6f3.js} +13 -13
  7. package/dist/{azure-openai-responses-xa4sh9f6.js → azure-openai-responses-c0yjmbfd.js} +8 -5
  8. package/dist/{boot-reembed-18pzsrxa.js → boot-reembed-62p0at2k.js} +6 -6
  9. package/dist/{boot-reembed-wpks2cj8.js → boot-reembed-xmfp6wdh.js} +7 -7
  10. package/dist/{boot-scrub-logs-n7szd57r.js → boot-scrub-logs-rr8q2dms.js} +5 -5
  11. package/dist/{claude-adapter-qz4r0ajt.js → claude-adapter-2y47mrkd.js} +9 -9
  12. package/dist/{cli-mhjnbgb6.js → cli-0rcyq6d9.js} +450 -186
  13. package/dist/{cli-ttkmehy0.js → cli-2q72qz2s.js} +274 -25
  14. package/dist/{cli-gztgc3hz.js → cli-2wadx7p2.js} +2 -2
  15. package/dist/cli-3fj60etf.js +153 -0
  16. package/dist/{cli-7ecgm5v0.js → cli-3kf51j15.js} +1 -1
  17. package/dist/{cli-vgexpfsr.js → cli-57khth04.js} +6 -3
  18. package/dist/{cli-2mbe7vk0.js → cli-5dsbcjjw.js} +1 -1
  19. package/dist/{cli-etr62zy6.js → cli-5kx36evn.js} +2 -2
  20. package/dist/{cli-v2tr6amf.js → cli-5n6e5yfn.js} +30 -8
  21. package/dist/{cli-hx02s9zq.js → cli-5v4rw6yd.js} +2 -2
  22. package/dist/{cli-v37yr6mf.js → cli-5ze9rv97.js} +4 -4
  23. package/dist/{cli-ch7t5v7n.js → cli-6map995v.js} +9 -4
  24. package/dist/{cli-h0457a67.js → cli-70xqj0z3.js} +3 -3
  25. package/dist/{cli-kk4f9r17.js → cli-72q8m8gk.js} +8 -6
  26. package/dist/{cli-7padk69a.js → cli-78xwvkhj.js} +2 -2
  27. package/dist/{cli-dxtxacy7.js → cli-9dr5qzc0.js} +45 -8
  28. package/dist/{cli-17zxdgsq.js → cli-a40rnf71.js} +6 -6
  29. package/dist/{cli-t53vnnxz.js → cli-a4jzdpa3.js} +2514 -1055
  30. package/dist/{cli-w10fkrf1.js → cli-akdvwc9v.js} +354 -115
  31. package/dist/{cli-1qkk5er0.js → cli-bmze986d.js} +1 -1
  32. package/dist/{cli-ga12dc1d.js → cli-bqw0mt1n.js} +3 -3
  33. package/dist/{cli-0sf92efp.js → cli-cdeg08wx.js} +1 -1
  34. package/dist/{cli-a8ynhkyj.js → cli-cvgjwnh1.js} +17 -15
  35. package/dist/{cli-9fxg3v5m.js → cli-d2tfkcga.js} +4 -4
  36. package/dist/{cli-nhcd7x43.js → cli-d3x3x1c9.js} +2 -2
  37. package/dist/{cli-6nh2qxvh.js → cli-darcwax3.js} +1 -1
  38. package/dist/{cli-yjbgmysx.js → cli-e7ckcg4v.js} +12 -12
  39. package/dist/{cli-4n2gcjpd.js → cli-efxfnq6q.js} +4 -3
  40. package/dist/{cli-z9xqqhfk.js → cli-er3a4bb0.js} +1 -1
  41. package/dist/{cli-xg2eezyv.js → cli-f1am9szv.js} +1 -1
  42. package/dist/{cli-xy4cwsm9.js → cli-fywms69x.js} +1 -1
  43. package/dist/{cli-33jj76y8.js → cli-g6b8x1h8.js} +1 -1
  44. package/dist/{cli-epsvdckx.js → cli-gm9cbhbq.js} +20 -10
  45. package/dist/{cli-rkndnn90.js → cli-k9qkf1hw.js} +6 -4
  46. package/dist/{cli-zejvt395.js → cli-kh3ba2zf.js} +1 -1
  47. package/dist/{cli-gb25p1h2.js → cli-nm5gtp1x.js} +2 -2
  48. package/dist/{cli-akxnpx17.js → cli-pm6xbh84.js} +1829 -1629
  49. package/dist/{cli-2k0ztbfp.js → cli-psh3c4va.js} +1 -1
  50. package/dist/{cli-39vgrsep.js → cli-qv61hp37.js} +2 -2
  51. package/dist/{cli-hv2fndhm.js → cli-r6kqqbj0.js} +6 -4
  52. package/dist/{cli-1y1cm570.js → cli-rzbpmxdr.js} +1 -1
  53. package/dist/{cli-mmrk00vp.js → cli-t1xze5qh.js} +1 -1
  54. package/dist/{cli-g252a9ky.js → cli-t55yw3a1.js} +2 -2
  55. package/dist/{cli-7bz8dzqa.js → cli-t76vw5db.js} +1184 -1522
  56. package/dist/{cli-4n4mdv21.js → cli-xpxde7rm.js} +7 -3
  57. package/dist/{cli-fpaa5k2q.js → cli-yw8vghx2.js} +54 -18
  58. package/dist/cli-zsspvvm2.js +490 -0
  59. package/dist/cli.js +27 -25
  60. package/dist/{codex-adapter-7v6t7ff6.js → codex-adapter-d24q75wk.js} +7 -7
  61. package/dist/{codex-hook-amndawyb.js → codex-hook-hq54t9ft.js} +2 -2
  62. package/dist/{codex-session-runner-e7j4khe2.js → codex-session-runner-g50vcsex.js} +7 -7
  63. package/dist/{commands-ex0k5tbf.js → commands-c3nrc5hg.js} +5 -5
  64. package/dist/{db-df7jatfc.js → db-nt7fg3tw.js} +5 -5
  65. package/dist/{google-generative-ai-y42hnw9p.js → google-generative-ai-hysrd8qx.js} +7 -5
  66. package/dist/{google-vertex-4sg66gb6.js → google-vertex-p5arrga0.js} +7 -5
  67. package/dist/{handlers-1j2cfqt2.js → handlers-fkr6swat.js} +13 -13
  68. package/dist/{hook-nx9a0mj3.js → hook-77wpvnjc.js} +7 -7
  69. package/dist/{hook-w6yaf6sy.js → hook-g019yehy.js} +8 -8
  70. package/dist/{http-4tz5h8wg.js → http-jewj0syk.js} +2993 -716
  71. package/dist/{index-0bpkzb09.js → index-070v4eyb.js} +3 -3
  72. package/dist/{index-0s67qv7h.js → index-6gm5he8h.js} +11 -11
  73. package/dist/{index-35gtv6gj.js → index-7n2xpbd4.js} +310 -40
  74. package/dist/{index-ker3gccb.js → index-9znhar3x.js} +4 -4
  75. package/dist/{index-5n2c8yay.js → index-hase6zbe.js} +2 -2
  76. package/dist/{index-kcf3tm9h.js → index-hfvggd0z.js} +12 -12
  77. package/dist/{index-7c0jqna0.js → index-hp1kdbjj.js} +13 -13
  78. package/dist/{keepalive-3j4a9168.js → keepalive-j0fjvqfd.js} +7 -7
  79. package/dist/{lead-6kpevymb.js → lead-1n8x30xe.js} +33 -33
  80. package/dist/{maintenance-m1k82ean.js → maintenance-gvev11sa.js} +7 -7
  81. package/dist/{mistral-conversations-bjkdfb6z.js → mistral-conversations-81fwav0j.js} +6 -6
  82. package/dist/{oauth-refresh-sweep-881k8e4q.js → oauth-refresh-sweep-s9ecsvh0.js} +6 -6
  83. package/dist/{onboard-c0ykffjn.js → onboard-pvm5b38w.js} +2 -2
  84. package/dist/{openai-codex-responses-xetseqvt.js → openai-codex-responses-5g27pd6f.js} +43 -23
  85. package/dist/{openai-completions-5r2g5axa.js → openai-completions-3vkmfz2a.js} +55 -11
  86. package/dist/{openai-responses-ce67hd23.js → openai-responses-dg4t7j7a.js} +8 -5
  87. package/dist/{openrouter-images-pzfp22jb.js → openrouter-images-g3gm8931.js} +1 -1
  88. package/dist/{otel-impl-sqagjerv.js → otel-impl-p6jvgd9c.js} +6 -4
  89. package/dist/{otel-3mp81ppd.js → otel-nqa12wf3.js} +2 -2
  90. package/dist/{pi-mono-adapter-k584k16g.js → pi-mono-adapter-t091s27g.js} +17117 -7517
  91. package/dist/{pricing-refresh-y82whbf9.js → pricing-refresh-k49rcyed.js} +7 -7
  92. package/dist/{rbac-roles-nvkqmzyd.js → rbac-roles-30pspvy7.js} +7 -7
  93. package/dist/{rbac-roles-4ht8gegc.js → rbac-roles-cr80g96t.js} +6 -6
  94. package/dist/{render-v2-wvqdgvvp.js → render-v2-xm457ng1.js} +8 -8
  95. package/dist/{seed-pricing-fy3rxhde.js → seed-pricing-yhpv35fr.js} +6 -6
  96. package/dist/{setup-ak5cnc6f.js → setup-nytnmwwr.js} +2 -2
  97. package/dist/{worker-d8769q8a.js → worker-msytr2cw.js} +33 -33
  98. package/openapi.json +34039 -11036
  99. package/package.json +8 -6
  100. package/src/apps/definition.ts +368 -26
  101. package/src/apps/row-store.ts +66 -10
  102. package/src/apps/schema-migrate.ts +95 -1
  103. package/src/apps/store.ts +13 -4
  104. package/src/apps/sync-run-as.ts +18 -0
  105. package/src/apps/sync.ts +934 -0
  106. package/src/apps/version.ts +16 -2
  107. package/src/assets/key.ts +8 -1
  108. package/src/be/asset-key-audit.ts +3 -1
  109. package/src/be/db-queries/mcp-oauth.ts +297 -24
  110. package/src/be/db.ts +42 -1
  111. package/src/be/migrations/129_asset_keys_apps_scripts.sql +161 -0
  112. package/src/be/scripts/db.ts +5 -2
  113. package/src/be/scripts/typecheck.ts +1 -0
  114. package/src/be/seed-scripts/catalog/app-sync-run.ts +32 -0
  115. package/src/be/seed-scripts/catalog/github-issues-pull.ts +102 -0
  116. package/src/be/seed-scripts/index.ts +18 -0
  117. package/src/be/seed-skills/index.ts +7 -0
  118. package/src/http/active-sessions.ts +26 -18
  119. package/src/http/agents.ts +94 -27
  120. package/src/http/api-keys.ts +91 -17
  121. package/src/http/approval-requests.ts +87 -10
  122. package/src/http/apps.ts +361 -53
  123. package/src/http/assets.ts +165 -31
  124. package/src/http/budgets.ts +7 -5
  125. package/src/http/codex-oauth-keep-warm.ts +21 -3
  126. package/src/http/config.ts +46 -16
  127. package/src/http/context.ts +33 -6
  128. package/src/http/ecosystem.ts +20 -6
  129. package/src/http/events.ts +24 -9
  130. package/src/http/favorites.ts +20 -6
  131. package/src/http/fs.ts +60 -17
  132. package/src/http/heartbeat.ts +18 -4
  133. package/src/http/inbox-state.ts +12 -6
  134. package/src/http/integrations.ts +25 -5
  135. package/src/http/kv.ts +36 -15
  136. package/src/http/mcp-bridge.ts +5 -1
  137. package/src/http/mcp-oauth.ts +332 -17
  138. package/src/http/mcp-servers.ts +56 -18
  139. package/src/http/memory.ts +282 -29
  140. package/src/http/metrics.ts +80 -17
  141. package/src/http/oauth-callback.ts +10 -4
  142. package/src/http/oauth-generic.ts +5 -1
  143. package/src/http/oauth-locks.ts +6 -3
  144. package/src/http/openapi.ts +57 -9
  145. package/src/http/page-proxy.ts +25 -5
  146. package/src/http/pages-public.ts +37 -20
  147. package/src/http/pages.ts +93 -28
  148. package/src/http/poll.ts +89 -5
  149. package/src/http/pricing.ts +9 -6
  150. package/src/http/prompt-templates.ts +85 -21
  151. package/src/http/route-def.ts +67 -4
  152. package/src/http/schedules.ts +63 -14
  153. package/src/http/script-connection-proxy.ts +30 -4
  154. package/src/http/script-connections.ts +393 -43
  155. package/src/http/script-runs.ts +73 -19
  156. package/src/http/scripts.ts +257 -39
  157. package/src/http/session-data.ts +87 -14
  158. package/src/http/sessions.ts +80 -5
  159. package/src/http/skills.ts +115 -35
  160. package/src/http/stats.ts +94 -13
  161. package/src/http/task-templates.ts +6 -4
  162. package/src/http/tasks.ts +230 -61
  163. package/src/http/trackers/jira.ts +90 -30
  164. package/src/http/trackers/linear.ts +46 -12
  165. package/src/http/users.ts +162 -25
  166. package/src/http/utils.ts +12 -2
  167. package/src/http/webhooks.ts +30 -16
  168. package/src/http/workflow-events.ts +18 -5
  169. package/src/http/workflows.ts +128 -39
  170. package/src/http/x.ts +37 -6
  171. package/src/oauth/ensure-mcp-token.ts +16 -1
  172. package/src/oauth/mcp-wrapper.ts +281 -26
  173. package/src/providers/pi-mono-adapter.ts +1 -1
  174. package/src/scripts-runtime/credential-broker/README.md +1 -1
  175. package/src/scripts-runtime/credential-broker/fetch-patch.ts +12 -2
  176. package/src/scripts-runtime/sdk-allowlist.ts +1 -0
  177. package/src/scripts-runtime/stdlib/fetch.ts +6 -0
  178. package/src/scripts-runtime/types/stdlib.d.ts +1 -0
  179. package/src/scripts-runtime/types/swarm-sdk.d.ts +1 -0
  180. package/src/server.ts +2 -0
  181. package/src/tests/apps-rbac.test.ts +110 -0
  182. package/src/tests/apps-spike2.test.ts +4 -1
  183. package/src/tests/apps-sync-engine.test.ts +2540 -0
  184. package/src/tests/apps-sync.test.ts +1627 -0
  185. package/src/tests/asset-key-api.test.ts +48 -2
  186. package/src/tests/asset-key-invariants.test.ts +92 -0
  187. package/src/tests/asset-key-migration.test.ts +174 -8
  188. package/src/tests/asset-key-normalization.test.ts +2 -0
  189. package/src/tests/credential-broker.test.ts +27 -2
  190. package/src/tests/mcp-oauth-dcr-reuse.test.ts +743 -0
  191. package/src/tests/mcp-oauth-ensure-token.test.ts +45 -0
  192. package/src/tests/mcp-oauth-manual-client.test.ts +135 -2
  193. package/src/tests/mcp-oauth-queries.test.ts +153 -0
  194. package/src/tests/mcp-oauth-wrapper.test.ts +432 -0
  195. package/src/tests/memory-http-recall-gating.test.ts +2 -0
  196. package/src/tests/openapi-response-contract.test.ts +138 -0
  197. package/src/tests/rbac-admission-e2e.test.ts +68 -0
  198. package/src/tests/script-connections.test.ts +3 -0
  199. package/src/tests/scripts-runtime-fetch.test.ts +121 -0
  200. package/src/tests/scripts-runtime-secret-egress.test.ts +4 -2
  201. package/src/tests/seed-scripts.test.ts +2 -2
  202. package/src/tests/swarm-tool-result-gate.test.ts +32 -0
  203. package/src/tests/task-working-dir.test.ts +8 -4
  204. package/src/tests/whoami-route.test.ts +127 -0
  205. package/src/tests/workflow-engine-v2.test.ts +80 -7
  206. package/src/tests/workflow-swarm-script.test.ts +104 -0
  207. package/src/tools/app-get.ts +10 -2
  208. package/src/tools/app-rollback.ts +1 -0
  209. package/src/tools/app-sync.ts +112 -0
  210. package/src/tools/script-common.ts +20 -0
  211. package/src/tools/tool-config.ts +2 -1
  212. package/src/tools/utils.ts +11 -0
  213. package/src/tools/workflows/create-workflow.ts +4 -1
  214. package/src/types.ts +1394 -1206
  215. package/src/utils/template.ts +8 -1
  216. package/src/utils/zod-openapi.ts +11 -0
  217. package/src/workflows/engine.ts +27 -4
  218. package/src/workflows/executors/swarm-script.ts +28 -0
  219. package/src/workflows/retry-poller.ts +19 -2
  220. package/templates/skills/apps/content.md +94 -5
  221. package/templates/skills/asset-namespaces/content.md +2 -2
  222. package/templates/skills/scheduled-task-resilience/SKILL.md +102 -0
  223. package/templates/skills/scheduled-task-resilience/config.json +14 -0
  224. package/templates/skills/scheduled-task-resilience/content.md +97 -0
  225. package/dist/cli-7wmybrt5.js +0 -115
  226. package/dist/cli-d91pvmq1.js +0 -14
package/src/types.ts CHANGED
@@ -1,6 +1,10 @@
1
- import * as z from "zod";
1
+ // z comes pre-extended with `.openapi()` — entity schemas here are named as
2
+ // OpenAPI components (`.openapi("AgentTask")`) so route response schemas that
3
+ // reference them emit `$ref`s and SDK generators produce named types.
4
+
2
5
  import { normalizeAssetKey } from "./assets/key";
3
6
  import { MAX_PROFILE_FILE_LENGTH } from "./utils/constants";
7
+ import { z } from "./utils/zod-openapi";
4
8
  // ─── Asset namespaces ──────────────────────────────────────────────────────
5
9
 
6
10
  export const AssetKeySchema = z
@@ -21,41 +25,55 @@ export const AssetKeySchema = z
21
25
  "Non-unique asset directory namespace (for example shared/ or personal/<user-id>/drafts/). Runtime write boundaries normalize and validate the canonical form.",
22
26
  );
23
27
 
24
- export const AssetEntityTypeSchema = z.enum(["task", "workflow", "schedule", "page", "file"]);
28
+ export const AssetEntityTypeSchema = z.enum([
29
+ "task",
30
+ "workflow",
31
+ "schedule",
32
+ "page",
33
+ "app",
34
+ "script",
35
+ "file",
36
+ ]);
25
37
  export type AssetEntityType = z.infer<typeof AssetEntityTypeSchema>;
26
38
 
27
- export const AssetProviderRefSchema = z.object({
28
- providerId: z.string(),
29
- orgId: z.string().optional(),
30
- driveId: z.string().optional(),
31
- providerKey: z.string(),
32
- });
39
+ export const AssetProviderRefSchema = z
40
+ .object({
41
+ providerId: z.string(),
42
+ orgId: z.string().optional(),
43
+ driveId: z.string().optional(),
44
+ providerKey: z.string(),
45
+ })
46
+ .openapi("AssetProviderRef");
33
47
  export type AssetProviderRef = z.infer<typeof AssetProviderRefSchema>;
34
48
 
35
- export const AssetKeyMappingSchema = z.object({
36
- id: z.string(),
37
- providerId: z.string(),
38
- providerOrgId: z.string().optional(),
39
- providerDriveId: z.string().optional(),
40
- providerKey: z.string(),
41
- key: AssetKeySchema,
42
- sourceEntityType: z.enum(["task-attachment", "external"]).optional(),
43
- sourceEntityId: z.string().optional(),
44
- createdAt: z.iso.datetime(),
45
- updatedAt: z.iso.datetime(),
46
- createdBy: z.string().optional(),
47
- updatedBy: z.string().optional(),
48
- });
49
+ export const AssetKeyMappingSchema = z
50
+ .object({
51
+ id: z.string(),
52
+ providerId: z.string(),
53
+ providerOrgId: z.string().optional(),
54
+ providerDriveId: z.string().optional(),
55
+ providerKey: z.string(),
56
+ key: AssetKeySchema,
57
+ sourceEntityType: z.enum(["task-attachment", "external"]).optional(),
58
+ sourceEntityId: z.string().optional(),
59
+ createdAt: z.iso.datetime(),
60
+ updatedAt: z.iso.datetime(),
61
+ createdBy: z.string().optional(),
62
+ updatedBy: z.string().optional(),
63
+ })
64
+ .openapi("AssetKeyMapping");
49
65
  export type AssetKeyMapping = z.infer<typeof AssetKeyMappingSchema>;
50
66
 
51
- export const AssetSummarySchema = z.object({
52
- entityType: AssetEntityTypeSchema,
53
- id: z.string(),
54
- key: AssetKeySchema,
55
- label: z.string(),
56
- updatedAt: z.string(),
57
- providerRef: AssetProviderRefSchema.optional(),
58
- });
67
+ export const AssetSummarySchema = z
68
+ .object({
69
+ entityType: AssetEntityTypeSchema,
70
+ id: z.string(),
71
+ key: AssetKeySchema,
72
+ label: z.string(),
73
+ updatedAt: z.string(),
74
+ providerRef: AssetProviderRefSchema.optional(),
75
+ })
76
+ .openapi("AssetSummary");
59
77
  export type AssetSummary = z.infer<typeof AssetSummarySchema>;
60
78
 
61
79
  // ─── Model Tiers ─────────────────────────────────────────────────────────────
@@ -267,29 +285,31 @@ export const InboxMessageStatusSchema = z.enum([
267
285
  "delegated",
268
286
  ]);
269
287
 
270
- export const InboxMessageSchema = z.object({
271
- id: z.uuid(),
272
- agentId: z.string(), // Lead agent who received this
273
- content: z.string().min(1), // The message content
274
- source: z.enum(["slack", "agentmail"]).default("slack"),
275
- status: InboxMessageStatusSchema.default("unread"),
288
+ export const InboxMessageSchema = z
289
+ .object({
290
+ id: z.uuid(),
291
+ agentId: z.string(), // Lead agent who received this
292
+ content: z.string().min(1), // The message content
293
+ source: z.enum(["slack", "agentmail"]).default("slack"),
294
+ status: InboxMessageStatusSchema.default("unread"),
276
295
 
277
- // Slack context (for replying)
278
- slackChannelId: z.string().optional(),
279
- slackThreadTs: z.string().optional(),
280
- slackUserId: z.string().optional(),
296
+ // Slack context (for replying)
297
+ slackChannelId: z.string().optional(),
298
+ slackThreadTs: z.string().optional(),
299
+ slackUserId: z.string().optional(),
281
300
 
282
- // Routing info
283
- matchedText: z.string().optional(), // Why it was routed here
301
+ // Routing info
302
+ matchedText: z.string().optional(), // Why it was routed here
284
303
 
285
- // Delegation tracking
286
- delegatedToTaskId: z.uuid().optional(), // If delegated, which task
287
- responseText: z.string().optional(), // If responded directly
304
+ // Delegation tracking
305
+ delegatedToTaskId: z.uuid().optional(), // If delegated, which task
306
+ responseText: z.string().optional(), // If responded directly
288
307
 
289
- // Timestamps
290
- createdAt: z.iso.datetime(),
291
- lastUpdatedAt: z.iso.datetime(),
292
- });
308
+ // Timestamps
309
+ createdAt: z.iso.datetime(),
310
+ lastUpdatedAt: z.iso.datetime(),
311
+ })
312
+ .openapi("InboxMessage");
293
313
 
294
314
  export type InboxMessageStatus = z.infer<typeof InboxMessageStatusSchema>;
295
315
  export type InboxMessage = z.infer<typeof InboxMessageSchema>;
@@ -348,24 +368,26 @@ export type SteeringStatus = z.infer<typeof SteeringStatusSchema>;
348
368
  export const SteeringSourceSchema = z.enum(["ui", "mcp", "script", "slack", "api"]);
349
369
  export type SteeringSource = z.infer<typeof SteeringSourceSchema>;
350
370
 
351
- export const SteeringMessageSchema = z.object({
352
- id: z.uuid(),
353
- taskId: z.uuid(),
354
- body: z.string().min(1),
355
- mode: SteerModeSchema,
356
- status: SteeringStatusSchema,
357
- deliveredMode: SteerModeSchema.optional(),
358
- source: SteeringSourceSchema,
359
- createdByKind: z.enum(["user", "agent", "system"]),
360
- createdByUserId: z.string().optional(),
361
- createdByAgentId: z.string().optional(),
362
- promotedTaskId: z.uuid().optional(),
363
- createdAt: z.iso.datetime(),
364
- deliveredAt: z.iso.datetime().optional(),
365
- handledAt: z.iso.datetime().optional(),
366
- /** accept-steer's optional note describing how the steering was incorporated. */
367
- handledNote: z.string().optional(),
368
- });
371
+ export const SteeringMessageSchema = z
372
+ .object({
373
+ id: z.uuid(),
374
+ taskId: z.uuid(),
375
+ body: z.string().min(1),
376
+ mode: SteerModeSchema,
377
+ status: SteeringStatusSchema,
378
+ deliveredMode: SteerModeSchema.optional(),
379
+ source: SteeringSourceSchema,
380
+ createdByKind: z.enum(["user", "agent", "system"]),
381
+ createdByUserId: z.string().optional(),
382
+ createdByAgentId: z.string().optional(),
383
+ promotedTaskId: z.uuid().optional(),
384
+ createdAt: z.iso.datetime(),
385
+ deliveredAt: z.iso.datetime().optional(),
386
+ handledAt: z.iso.datetime().optional(),
387
+ /** accept-steer's optional note describing how the steering was incorporated. */
388
+ handledNote: z.string().optional(),
389
+ })
390
+ .openapi("SteeringMessage");
369
391
  export type SteeringMessage = z.infer<typeof SteeringMessageSchema>;
370
392
 
371
393
  export const SteerOutcomeSchema = z.enum(["steered", "queued", "promoted"]);
@@ -375,13 +397,15 @@ export type SteerOutcome = z.infer<typeof SteerOutcomeSchema>;
375
397
  export const OnUnsupportedSchema = z.enum(["degrade", "fail"]).default("degrade");
376
398
  export type OnUnsupported = z.infer<typeof OnUnsupportedSchema>;
377
399
 
378
- export const SteerResultSchema = z.object({
379
- outcome: SteerOutcomeSchema,
380
- steeringMessageId: z.uuid().optional(),
381
- promotedTaskId: z.uuid().optional(),
382
- effectiveMode: SteerModeSchema,
383
- degradedFrom: SteerModeSchema.optional(),
384
- });
400
+ export const SteerResultSchema = z
401
+ .object({
402
+ outcome: SteerOutcomeSchema,
403
+ steeringMessageId: z.uuid().optional(),
404
+ promotedTaskId: z.uuid().optional(),
405
+ effectiveMode: SteerModeSchema,
406
+ degradedFrom: SteerModeSchema.optional(),
407
+ })
408
+ .openapi("SteerResult");
385
409
  export type SteerResult = z.infer<typeof SteerResultSchema>;
386
410
 
387
411
  /**
@@ -428,11 +452,13 @@ export type ProviderMetaMap = {
428
452
  opencode: NoProviderMeta;
429
453
  };
430
454
 
431
- export const FollowUpConfigSchema = z.object({
432
- disabled: z.boolean().optional(),
433
- onCompleted: z.string().max(4000).optional(),
434
- onFailed: z.string().max(4000).optional(),
435
- });
455
+ export const FollowUpConfigSchema = z
456
+ .object({
457
+ disabled: z.boolean().optional(),
458
+ onCompleted: z.string().max(4000).optional(),
459
+ onFailed: z.string().max(4000).optional(),
460
+ })
461
+ .openapi("FollowUpConfig");
436
462
  export type FollowUpConfig = z.infer<typeof FollowUpConfigSchema>;
437
463
 
438
464
  // Routing-affinity snapshot for interrupted/pooled tasks (routing-affinity
@@ -442,153 +468,170 @@ export type FollowUpConfig = z.infer<typeof FollowUpConfigSchema>;
442
468
  // declares `capabilities`); `harnessProvider` is informational only (native
443
469
  // session resume is deprecated, so it is never enforced by the eligibility
444
470
  // gate). See `isAgentEligibleForTask` in `src/be/db.ts`.
445
- export const RoutingAffinitySchema = z.object({
446
- sourceAgentId: z.string().optional(),
447
- role: z.string().max(100).optional(),
448
- harnessProvider: ProviderNameSchema.optional(),
449
- capabilities: z.array(z.string()).default([]),
450
- });
471
+ export const RoutingAffinitySchema = z
472
+ .object({
473
+ sourceAgentId: z.string().optional(),
474
+ role: z.string().max(100).optional(),
475
+ harnessProvider: ProviderNameSchema.optional(),
476
+ capabilities: z.array(z.string()).default([]),
477
+ })
478
+ .openapi("RoutingAffinity");
451
479
  export type RoutingAffinity = z.infer<typeof RoutingAffinitySchema>;
452
480
 
453
- export const AgentTaskSchema = z.object({
454
- id: z.uuid(),
455
- key: AssetKeySchema,
456
- // Agent-id fields are plain strings, NOT .uuid(): agents may join with custom
457
- // IDs (AGENT_ID env / join-swarm agentId), and a UUID constraint here makes MCP
458
- // tool responses fail output validation after the write already applied.
459
- agentId: z.string().nullable(), // Nullable for unassigned tasks
460
- creatorAgentId: z.string().optional(), // Who created this task (optional for Slack/API)
461
- task: z.string().min(1),
462
- title: z.string().optional(), // Human-facing display title override (e.g. session rename); falls back to `task` when unset
463
- status: AgentTaskStatusSchema,
464
- source: AgentTaskSourceSchema.default("mcp"),
465
-
466
- // Task metadata
467
- taskType: z.string().max(50).optional(), // e.g., "bug", "feature", "chore"
468
- tags: z.array(z.string()).default([]), // e.g., ["urgent", "frontend"]
469
- priority: z.number().int().min(0).max(100).default(50),
470
- dependsOn: z.array(z.uuid()).default([]), // Task IDs this depends on
471
-
472
- // Acceptance tracking
473
- offeredTo: z.string().optional(), // Agent the task was offered to
474
- offeredAt: z.iso.datetime().optional(),
475
- acceptedAt: z.iso.datetime().optional(),
476
- rejectionReason: z.string().optional(),
477
-
478
- // Timestamps
479
- createdAt: z.iso.datetime().default(() => new Date().toISOString()),
480
- lastUpdatedAt: z.iso.datetime().default(() => new Date().toISOString()),
481
- finishedAt: z.iso.datetime().optional(),
482
- notifiedAt: z.iso.datetime().optional(),
483
-
484
- // Completion data
485
- failureReason: z.string().optional(),
486
- output: z.string().optional(),
487
- progress: z.string().optional(),
488
-
489
- // Slack-specific metadata (optional)
490
- slackChannelId: z.string().optional(),
491
- slackThreadTs: z.string().optional(),
492
- slackTriggerMessageTs: z.string().optional(),
493
- slackUserId: z.string().optional(),
494
- slackReplySent: z.boolean().default(false),
495
- slackProgressMessageTs: z.string().optional(),
496
- slackTreeRootMessageTs: z.string().optional(),
497
-
498
- // VCS metadata (GitHub / GitLab — provider-agnostic)
499
- vcsProvider: z.enum(["github", "gitlab"]).optional(),
500
- vcsRepo: z.string().optional(),
501
- vcsEventType: z.string().optional(),
502
- vcsNumber: z.number().int().optional(),
503
- vcsCommentId: z.number().int().optional(),
504
- vcsAuthor: z.string().optional(),
505
- vcsUrl: z.string().optional(),
506
- vcsInstallationId: z.number().int().optional(),
507
- vcsNodeId: z.string().optional(),
508
-
509
- // AgentMail-specific metadata (optional)
510
- agentmailInboxId: z.string().optional(),
511
- agentmailMessageId: z.string().optional(),
512
- agentmailThreadId: z.string().optional(),
513
-
514
- // Mention-to-task metadata (optional)
515
- mentionMessageId: z.uuid().optional(),
516
- mentionChannelId: z.uuid().optional(),
517
-
518
- // Working directory (optional — must be an absolute path for the agent process)
519
- dir: z.string().min(1).startsWith("/").optional(),
520
-
521
- // Session attachment (optional)
522
- parentTaskId: z.uuid().optional(),
523
- claudeSessionId: z.string().optional(),
524
-
525
- // Model selection (optional — provider-specific; can be "opus", "gpt-4o",
526
- // "openrouter/openai/gpt-5-nano", etc. depending on HARNESS_PROVIDER).
527
- // Prefer modelTier for portable task intent; model is a concrete override
528
- // interpreted by the claiming worker's harness and never switches provider.
529
- model: z.string().optional(),
530
- modelTier: ModelTierSchema.optional(),
531
- effort: ReasoningEffortSchema.optional(),
532
-
533
- // Schedule linking (optional — set when task was created by a schedule)
534
- scheduleId: z.uuid().optional(),
535
-
536
- // Workflow linking (optional — set when task was created by a workflow)
537
- workflowRunId: z.string().uuid().nullable().optional(),
538
- workflowRunStepId: z.string().uuid().nullable().optional(),
539
-
540
- // Cross-ingress context key — uniform identifier for the "context entity"
541
- // (Slack thread, GitHub issue, Linear issue, schedule, workflow run, ...).
542
- // See src/tasks/context-key.ts. Nullable: legacy rows stay NULL.
543
- contextKey: z.string().optional(),
544
-
545
- // Structured output schema (optional — JSON Schema that task output must conform to)
546
- outputSchema: z.record(z.string(), z.unknown()).optional(),
547
-
548
- // Lead follow-up control (optional — null/undefined preserves default behavior)
549
- followUpConfig: FollowUpConfigSchema.optional(),
550
-
551
- // Pause tracking
552
- wasPaused: z.boolean().default(false),
553
-
554
- // Context usage aggregates
555
- compactionCount: z.number().int().min(0).optional(),
556
- peakContextPercent: z.number().min(0).max(100).optional(),
557
- // Migration 063: renamed from totalContextTokensUsed. Semantic is now a
558
- // monotonic max across the task's snapshots — "high water mark" rather than
559
- // "latest known".
560
- peakContextTokens: z.number().int().min(0).optional(),
561
- contextWindowSize: z.number().int().min(0).optional(),
562
-
563
- // Credential tracking
564
- credentialKeySuffix: z.string().optional(),
565
- credentialKeyType: z.string().optional(),
566
-
567
- // User identity — canonical user who requested this task
568
- requestedByUserId: z.string().optional(),
569
-
570
- // agent-swarm package version at task creation time. Enables benchmarking
571
- // performance across releases. Nullable for rows created before tracking was added.
572
- swarmVersion: z.string().optional(),
573
-
574
- // Provider tracking — which harness provider ran this task
575
- provider: ProviderNameSchema.optional(),
576
- providerMeta: z.record(z.string(), z.unknown()).optional(),
577
-
578
- // Harness variant — sub-variant within a provider (e.g. "bridge" vs "stock" for claude)
579
- harnessVariant: z.string().optional(),
580
- harnessVariantMeta: z.record(z.string(), z.unknown()).optional(),
581
-
582
- // Aggregated session cost for task list/read models. Undefined means no
583
- // session cost rows have been recorded for this task.
584
- totalCostUsd: z.number().min(0).optional(),
585
-
586
- // Routing-affinity snapshot (nullable) — gates which agents may claim/
587
- // auto-claim this task via the pool. Undefined = untagged, unchanged
588
- // behavior. Inherited from parentTaskId when not explicitly set (see
589
- // `createTaskExtended` in src/be/db.ts). See `isAgentEligibleForTask`.
590
- routingAffinity: RoutingAffinitySchema.optional(),
591
- });
481
+ export const AgentTaskSchema = z
482
+ .object({
483
+ id: z.uuid(),
484
+ key: AssetKeySchema,
485
+ // Agent-id fields are plain strings, NOT .uuid(): agents may join with custom
486
+ // IDs (AGENT_ID env / join-swarm agentId), and a UUID constraint here makes MCP
487
+ // tool responses fail output validation after the write already applied.
488
+ agentId: z.string().nullable(), // Nullable for unassigned tasks
489
+ creatorAgentId: z.string().optional(), // Who created this task (optional for Slack/API)
490
+ task: z.string().min(1),
491
+ title: z.string().optional(), // Human-facing display title override (e.g. session rename); falls back to `task` when unset
492
+ status: AgentTaskStatusSchema,
493
+ source: AgentTaskSourceSchema.default("mcp"),
494
+
495
+ // Task metadata
496
+ taskType: z.string().max(50).optional(), // e.g., "bug", "feature", "chore"
497
+ tags: z.array(z.string()).default([]), // e.g., ["urgent", "frontend"]
498
+ priority: z.number().int().min(0).max(100).default(50),
499
+ // Task IDs this depends on. z.string(), not z.uuid(): the create-task
500
+ // body accepts arbitrary strings and the DB stores them verbatim, so a
501
+ // uuid pin here would make response validation reject honest rows.
502
+ dependsOn: z.array(z.string()).default([]),
503
+
504
+ // Acceptance tracking
505
+ offeredTo: z.string().optional(), // Agent the task was offered to
506
+ offeredAt: z.iso.datetime().optional(),
507
+ acceptedAt: z.iso.datetime().optional(),
508
+ rejectionReason: z.string().optional(),
509
+
510
+ // Timestamps. No `.default(() => now)`: rows always carry these, and a
511
+ // function default gets EVALUATED at OpenAPI generation time — baking a
512
+ // wall-clock value into openapi.json and making generation
513
+ // non-reproducible (freshness gate flake).
514
+ createdAt: z.iso.datetime(),
515
+ lastUpdatedAt: z.iso.datetime(),
516
+ finishedAt: z.iso.datetime().optional(),
517
+ notifiedAt: z.iso.datetime().optional(),
518
+
519
+ // Completion data
520
+ failureReason: z.string().optional(),
521
+ output: z.string().optional(),
522
+ progress: z.string().optional(),
523
+
524
+ // Slack-specific metadata (optional)
525
+ slackChannelId: z.string().optional(),
526
+ slackThreadTs: z.string().optional(),
527
+ slackTriggerMessageTs: z.string().optional(),
528
+ slackUserId: z.string().optional(),
529
+ slackReplySent: z.boolean().default(false),
530
+ slackProgressMessageTs: z.string().optional(),
531
+ slackTreeRootMessageTs: z.string().optional(),
532
+
533
+ // VCS metadata (GitHub / GitLab — provider-agnostic)
534
+ vcsProvider: z.enum(["github", "gitlab"]).optional(),
535
+ vcsRepo: z.string().optional(),
536
+ vcsEventType: z.string().optional(),
537
+ vcsNumber: z.number().int().optional(),
538
+ vcsCommentId: z.number().int().optional(),
539
+ vcsAuthor: z.string().optional(),
540
+ vcsUrl: z.string().optional(),
541
+ vcsInstallationId: z.number().int().optional(),
542
+ vcsNodeId: z.string().optional(),
543
+
544
+ // AgentMail-specific metadata (optional)
545
+ agentmailInboxId: z.string().optional(),
546
+ agentmailMessageId: z.string().optional(),
547
+ agentmailThreadId: z.string().optional(),
548
+
549
+ // Mention-to-task metadata (optional). Plain strings, not z.uuid():
550
+ // Slack channel/message IDs (e.g. "C0AR967K0KZ") are not UUIDs — a uuid
551
+ // pin here makes response validation reject honest Slack-originated rows
552
+ // (same trap as the MCP tool output schemas, see get-task-details).
553
+ mentionMessageId: z.string().optional(),
554
+ mentionChannelId: z.string().optional(),
555
+
556
+ // Working directory (optional — SHOULD be an absolute path, but the
557
+ // create-task body accepts any string and the DB stores it verbatim, so
558
+ // the row contract cannot pin the format (see dependsOn note above).
559
+ dir: z.string().min(1).optional(),
560
+
561
+ // Session attachment (optional). z.string(), not z.uuid(): accepted
562
+ // verbatim from the create-task body (see dependsOn note above).
563
+ parentTaskId: z.string().optional(),
564
+ claudeSessionId: z.string().optional(),
565
+
566
+ // Model selection (optional — provider-specific; can be "opus", "gpt-4o",
567
+ // "openrouter/openai/gpt-5-nano", etc. depending on HARNESS_PROVIDER).
568
+ // Prefer modelTier for portable task intent; model is a concrete override
569
+ // interpreted by the claiming worker's harness and never switches provider.
570
+ model: z.string().optional(),
571
+ modelTier: ModelTierSchema.optional(),
572
+ effort: ReasoningEffortSchema.optional(),
573
+
574
+ // Schedule linking (optional — set when task was created by a schedule).
575
+ // z.string(): also reachable verbatim from the create-task query param.
576
+ scheduleId: z.string().optional(),
577
+
578
+ // Workflow linking (optional — set when task was created by a workflow)
579
+ workflowRunId: z.string().uuid().nullable().optional(),
580
+ workflowRunStepId: z.string().uuid().nullable().optional(),
581
+
582
+ // Cross-ingress context key — uniform identifier for the "context entity"
583
+ // (Slack thread, GitHub issue, Linear issue, schedule, workflow run, ...).
584
+ // See src/tasks/context-key.ts. Nullable: legacy rows stay NULL.
585
+ contextKey: z.string().optional(),
586
+
587
+ // Structured output schema (optional — JSON Schema that task output must conform to)
588
+ outputSchema: z.record(z.string(), z.unknown()).optional(),
589
+
590
+ // Lead follow-up control (optional — null/undefined preserves default behavior)
591
+ followUpConfig: FollowUpConfigSchema.optional(),
592
+
593
+ // Pause tracking
594
+ wasPaused: z.boolean().default(false),
595
+
596
+ // Context usage aggregates
597
+ compactionCount: z.number().int().min(0).optional(),
598
+ peakContextPercent: z.number().min(0).max(100).optional(),
599
+ // Migration 063: renamed from totalContextTokensUsed. Semantic is now a
600
+ // monotonic max across the task's snapshots — "high water mark" rather than
601
+ // "latest known".
602
+ peakContextTokens: z.number().int().min(0).optional(),
603
+ contextWindowSize: z.number().int().min(0).optional(),
604
+
605
+ // Credential tracking
606
+ credentialKeySuffix: z.string().optional(),
607
+ credentialKeyType: z.string().optional(),
608
+
609
+ // User identity — canonical user who requested this task
610
+ requestedByUserId: z.string().optional(),
611
+
612
+ // agent-swarm package version at task creation time. Enables benchmarking
613
+ // performance across releases. Nullable for rows created before tracking was added.
614
+ swarmVersion: z.string().optional(),
615
+
616
+ // Provider tracking — which harness provider ran this task
617
+ provider: ProviderNameSchema.optional(),
618
+ providerMeta: z.record(z.string(), z.unknown()).optional(),
619
+
620
+ // Harness variant — sub-variant within a provider (e.g. "bridge" vs "stock" for claude)
621
+ harnessVariant: z.string().optional(),
622
+ harnessVariantMeta: z.record(z.string(), z.unknown()).optional(),
623
+
624
+ // Aggregated session cost for task list/read models. Undefined means no
625
+ // session cost rows have been recorded for this task.
626
+ totalCostUsd: z.number().min(0).optional(),
627
+
628
+ // Routing-affinity snapshot (nullable) — gates which agents may claim/
629
+ // auto-claim this task via the pool. Undefined = untagged, unchanged
630
+ // behavior. Inherited from parentTaskId when not explicitly set (see
631
+ // `createTaskExtended` in src/be/db.ts). See `isAgentEligibleForTask`.
632
+ routingAffinity: RoutingAffinitySchema.optional(),
633
+ })
634
+ .openapi("AgentTask");
592
635
 
593
636
  // ============================================================================
594
637
  // Task Attachments (Phase 1 — pointer-based artifacts)
@@ -656,55 +699,59 @@ export const AttachmentInputSchema = z.discriminatedUnion("kind", [
656
699
  ]);
657
700
  export type AttachmentInput = z.infer<typeof AttachmentInputSchema>;
658
701
 
659
- export const TaskAttachmentSchema = z.object({
660
- id: z.uuid(),
661
- taskId: z.uuid(),
662
- agentId: z.string().nullable(),
663
- name: z.string(),
664
- kind: TaskAttachmentKindSchema,
665
- url: z.string().optional(),
666
- path: z.string().optional(),
667
- pageId: z.string().optional(),
668
- providerId: z.string().optional(),
669
- providerKey: z.string().optional(),
670
- capabilities: z.record(z.string(), z.unknown()).optional(),
671
- // agent-fs only — pair with `path` to build a public live-host URL.
672
- orgId: z.string().optional(),
673
- driveId: z.string().optional(),
674
- mimeType: z.string().optional(),
675
- sizeBytes: z.number().int().min(0).optional(),
676
- sha256: z.string().optional(),
677
- intent: z.string().optional(),
678
- description: z.string().optional(),
679
- isPrimary: z.boolean().default(false),
680
- createdAt: z.iso.datetime(),
681
- createdBy: z.string().optional(),
682
- updatedBy: z.string().optional(),
683
- });
702
+ export const TaskAttachmentSchema = z
703
+ .object({
704
+ id: z.uuid(),
705
+ taskId: z.uuid(),
706
+ agentId: z.string().nullable(),
707
+ name: z.string(),
708
+ kind: TaskAttachmentKindSchema,
709
+ url: z.string().optional(),
710
+ path: z.string().optional(),
711
+ pageId: z.string().optional(),
712
+ providerId: z.string().optional(),
713
+ providerKey: z.string().optional(),
714
+ capabilities: z.record(z.string(), z.unknown()).optional(),
715
+ // agent-fs only — pair with `path` to build a public live-host URL.
716
+ orgId: z.string().optional(),
717
+ driveId: z.string().optional(),
718
+ mimeType: z.string().optional(),
719
+ sizeBytes: z.number().int().min(0).optional(),
720
+ sha256: z.string().optional(),
721
+ intent: z.string().optional(),
722
+ description: z.string().optional(),
723
+ isPrimary: z.boolean().default(false),
724
+ createdAt: z.iso.datetime(),
725
+ createdBy: z.string().optional(),
726
+ updatedBy: z.string().optional(),
727
+ })
728
+ .openapi("TaskAttachment");
684
729
  export type TaskAttachment = z.infer<typeof TaskAttachmentSchema>;
685
730
 
686
731
  // ============================================================================
687
732
  // User Identity Types
688
733
  // ============================================================================
689
734
 
690
- export const UserSchema = z.object({
691
- id: z.string(),
692
- name: z.string().min(1),
693
- email: z.string().optional(),
694
- role: z.string().optional(),
695
- notes: z.string().optional(),
696
- emailAliases: z.array(z.string()).default([]),
697
- preferredChannel: z.string().default("slack"),
698
- timezone: z.string().optional(),
699
- // Phase 064: free-form JSON for operator notes + integration hints.
700
- metadata: z.record(z.string(), z.unknown()).optional(),
701
- // NULL = unlimited (Phase 064).
702
- dailyBudgetUsd: z.number().nullable().optional(),
703
- // Lifecycle (Phase 064). CHECK constraint enforces these three values.
704
- status: z.enum(["invited", "active", "suspended"]).default("active"),
705
- createdAt: z.iso.datetime(),
706
- lastUpdatedAt: z.iso.datetime(),
707
- });
735
+ export const UserSchema = z
736
+ .object({
737
+ id: z.string(),
738
+ name: z.string().min(1),
739
+ email: z.string().optional(),
740
+ role: z.string().optional(),
741
+ notes: z.string().optional(),
742
+ emailAliases: z.array(z.string()).default([]),
743
+ preferredChannel: z.string().default("slack"),
744
+ timezone: z.string().optional(),
745
+ // Phase 064: free-form JSON for operator notes + integration hints.
746
+ metadata: z.record(z.string(), z.unknown()).optional(),
747
+ // NULL = unlimited (Phase 064).
748
+ dailyBudgetUsd: z.number().nullable().optional(),
749
+ // Lifecycle (Phase 064). CHECK constraint enforces these three values.
750
+ status: z.enum(["invited", "active", "suspended"]).default("active"),
751
+ createdAt: z.iso.datetime(),
752
+ lastUpdatedAt: z.iso.datetime(),
753
+ })
754
+ .openapi("User");
708
755
 
709
756
  export type User = z.infer<typeof UserSchema>;
710
757
 
@@ -756,18 +803,20 @@ export type InboxItemType = z.infer<typeof InboxItemTypeSchema>;
756
803
  export const InboxItemStatusSchema = z.enum(["open", "snoozed", "dismissed", "done"]);
757
804
  export type InboxItemStatus = z.infer<typeof InboxItemStatusSchema>;
758
805
 
759
- export const InboxItemStateSchema = z.object({
760
- id: z.string(),
761
- userId: z.string(),
762
- itemType: InboxItemTypeSchema,
763
- itemId: z.string(),
764
- status: InboxItemStatusSchema,
765
- snoozeUntil: z.string().optional(),
766
- dismissedAt: z.string().optional(),
767
- doneAt: z.string().optional(),
768
- createdAt: z.string(),
769
- lastUpdatedAt: z.string(),
770
- });
806
+ export const InboxItemStateSchema = z
807
+ .object({
808
+ id: z.string(),
809
+ userId: z.string(),
810
+ itemType: InboxItemTypeSchema,
811
+ itemId: z.string(),
812
+ status: InboxItemStatusSchema,
813
+ snoozeUntil: z.string().optional(),
814
+ dismissedAt: z.string().optional(),
815
+ doneAt: z.string().optional(),
816
+ createdAt: z.string(),
817
+ lastUpdatedAt: z.string(),
818
+ })
819
+ .openapi("InboxItemState");
771
820
  export type InboxItemState = z.infer<typeof InboxItemStateSchema>;
772
821
 
773
822
  // ============================================================================
@@ -777,16 +826,18 @@ export type InboxItemState = z.infer<typeof InboxItemStateSchema>;
777
826
  export const FavoriteItemTypeSchema = z.enum(["page", "workflow", "schedule"]);
778
827
  export type FavoriteItemType = z.infer<typeof FavoriteItemTypeSchema>;
779
828
 
780
- export const UserFavoriteSchema = z.object({
781
- id: z.string(),
782
- userId: z.string().optional(),
783
- itemType: FavoriteItemTypeSchema,
784
- itemId: z.string(),
785
- createdAt: z.string(),
786
- lastUpdatedAt: z.string(),
787
- createdBy: z.string().optional(),
788
- updatedBy: z.string().optional(),
789
- });
829
+ export const UserFavoriteSchema = z
830
+ .object({
831
+ id: z.string(),
832
+ userId: z.string().optional(),
833
+ itemType: FavoriteItemTypeSchema,
834
+ itemId: z.string(),
835
+ createdAt: z.string(),
836
+ lastUpdatedAt: z.string(),
837
+ createdBy: z.string().optional(),
838
+ updatedBy: z.string().optional(),
839
+ })
840
+ .openapi("UserFavorite");
790
841
  export type UserFavorite = z.infer<typeof UserFavoriteSchema>;
791
842
 
792
843
  // ============================================================================
@@ -800,17 +851,19 @@ export type UserFavorite = z.infer<typeof UserFavoriteSchema>;
800
851
  export const TaskTemplateKindSchema = z.enum(["task", "workflow", "schedule"]);
801
852
  export type TaskTemplateKind = z.infer<typeof TaskTemplateKindSchema>;
802
853
 
803
- export const TaskTemplateSchema = z.object({
804
- id: z.string(),
805
- title: z.string().min(1),
806
- description: z.string(),
807
- prompt: z.string(),
808
- kind: TaskTemplateKindSchema.default("task"),
809
- payload: z.record(z.string(), z.unknown()).default({}),
810
- category: z.string().optional(),
811
- tags: z.array(z.string()).default([]),
812
- createdAt: z.string(),
813
- });
854
+ export const TaskTemplateSchema = z
855
+ .object({
856
+ id: z.string(),
857
+ title: z.string().min(1),
858
+ description: z.string(),
859
+ prompt: z.string(),
860
+ kind: TaskTemplateKindSchema.default("task"),
861
+ payload: z.record(z.string(), z.unknown()).default({}),
862
+ category: z.string().optional(),
863
+ tags: z.array(z.string()).default([]),
864
+ createdAt: z.string(),
865
+ })
866
+ .openapi("TaskTemplate");
814
867
  export type TaskTemplate = z.infer<typeof TaskTemplateSchema>;
815
868
 
816
869
  export const AgentStatusSchema = z.enum(["idle", "busy", "offline", "waiting_for_credentials"]);
@@ -834,78 +887,82 @@ export const AgentAvatarSchema = z.discriminatedUnion("type", [
834
887
  ]);
835
888
  export type AgentAvatar = z.infer<typeof AgentAvatarSchema>;
836
889
 
837
- export const AgentSchema = z.object({
838
- // Plain string, NOT .uuid(): agents may join with custom IDs (AGENT_ID env /
839
- // join-swarm agentId).
840
- id: z.string(),
841
- name: z.string().min(1),
842
- isLead: z.boolean().default(false),
843
- status: AgentStatusSchema,
844
-
845
- // Profile fields
846
- description: z.string().optional(),
847
- role: z.string().max(100).optional(), // Free-form, e.g., "frontend dev"
848
- capabilities: z.array(z.string()).default([]), // e.g., ["typescript", "react"]
849
-
850
- // Personal CLAUDE.md content (character cap, not a byte cap)
851
- claudeMd: z.string().max(MAX_PROFILE_FILE_LENGTH).optional(),
852
-
853
- // Soul: Persona, behavioral directives (injected via --append-system-prompt)
854
- soulMd: z.string().max(MAX_PROFILE_FILE_LENGTH).optional(),
855
- // Identity: Expertise, working style, self-evolution notes (injected via --append-system-prompt)
856
- identityMd: z.string().max(MAX_PROFILE_FILE_LENGTH).optional(),
857
- // Setup script: Runs at container start, agent-evolved (synced to /workspace/start-up.sh)
858
- setupScript: z.string().max(MAX_PROFILE_FILE_LENGTH).optional(),
859
- // Tools/environment reference: Operational knowledge (synced to /workspace/TOOLS.md)
860
- toolsMd: z.string().max(MAX_PROFILE_FILE_LENGTH).optional(),
861
- // Heartbeat checklist: Standing orders checked periodically (synced to /workspace/HEARTBEAT.md)
862
- heartbeatMd: z.string().max(MAX_PROFILE_FILE_LENGTH).optional(),
863
-
864
- // Concurrency limit (defaults to 1 for backwards compatibility)
865
- maxTasks: z.number().int().min(1).max(100).optional(),
866
-
867
- // Polling limit tracking (consecutive empty polls)
868
- emptyPollCount: z.number().int().min(0).optional(),
869
-
870
- // Last session activity timestamp (updated on tool calls, task updates, etc.)
871
- lastActivityAt: z.iso.datetime().optional(),
872
-
873
- // Harness provider this agent runs (claude, opencode, codex, ...)
874
- provider: ProviderNameSchema.optional(),
875
-
876
- // Phase 1.5 (cloud-personalization): harness provider pushed by the worker
877
- // on registration. Mirrors `provider` but lives in its own column so the
878
- // server can answer "what harnesses are deployed?" without joining
879
- // anywhere else, and so an operator can re-assign via
880
- // PATCH /api/agents/:id/harness-provider without restarting the worker.
881
- // Worker boot path is NOT yet rewritten (DES-359 tracks that) — the
882
- // PATCH is a planning/forecast mechanism today; on next worker restart,
883
- // the env-driven value wins.
884
- harnessProvider: ProviderNameSchema.nullable().optional(),
885
-
886
- // Env-var names the worker is blocked on when status is
887
- // `waiting_for_credentials`. Null otherwise.
888
- credentialMissing: z.array(z.string()).nullable().optional(),
889
-
890
- // Worker-self-reported credential snapshot for this agent's harness.
891
- // Pairs with `harnessProvider`. Null = unreported (worker hasn't booted
892
- // yet, or CRED_CHECK_DISABLE=1 was set). Migration 055 adds the column.
893
- credStatus: z
894
- .lazy(() => AgentCredStatusSchema)
895
- .nullable()
896
- .optional(),
897
-
898
- // Custom avatar (icon + color). Null/missing = fall back to the
899
- // deterministic hash-derived icon and color (see apps/ui/src/lib/agent-icon.ts
900
- // and agent-color.ts). Migration 119 adds the column.
901
- avatar: z
902
- .lazy(() => AgentAvatarSchema)
903
- .nullable()
904
- .optional(),
905
-
906
- createdAt: z.iso.datetime().default(() => new Date().toISOString()),
907
- lastUpdatedAt: z.iso.datetime().default(() => new Date().toISOString()),
908
- });
890
+ export const AgentSchema = z
891
+ .object({
892
+ // Plain string, NOT .uuid(): agents may join with custom IDs (AGENT_ID env /
893
+ // join-swarm agentId).
894
+ id: z.string(),
895
+ name: z.string().min(1),
896
+ isLead: z.boolean().default(false),
897
+ status: AgentStatusSchema,
898
+
899
+ // Profile fields
900
+ description: z.string().optional(),
901
+ role: z.string().max(100).optional(), // Free-form, e.g., "frontend dev"
902
+ capabilities: z.array(z.string()).default([]), // e.g., ["typescript", "react"]
903
+
904
+ // Personal CLAUDE.md content (character cap, not a byte cap)
905
+ claudeMd: z.string().max(MAX_PROFILE_FILE_LENGTH).optional(),
906
+
907
+ // Soul: Persona, behavioral directives (injected via --append-system-prompt)
908
+ soulMd: z.string().max(MAX_PROFILE_FILE_LENGTH).optional(),
909
+ // Identity: Expertise, working style, self-evolution notes (injected via --append-system-prompt)
910
+ identityMd: z.string().max(MAX_PROFILE_FILE_LENGTH).optional(),
911
+ // Setup script: Runs at container start, agent-evolved (synced to /workspace/start-up.sh)
912
+ setupScript: z.string().max(MAX_PROFILE_FILE_LENGTH).optional(),
913
+ // Tools/environment reference: Operational knowledge (synced to /workspace/TOOLS.md)
914
+ toolsMd: z.string().max(MAX_PROFILE_FILE_LENGTH).optional(),
915
+ // Heartbeat checklist: Standing orders checked periodically (synced to /workspace/HEARTBEAT.md)
916
+ heartbeatMd: z.string().max(MAX_PROFILE_FILE_LENGTH).optional(),
917
+
918
+ // Concurrency limit (defaults to 1 for backwards compatibility)
919
+ maxTasks: z.number().int().min(1).max(100).optional(),
920
+
921
+ // Polling limit tracking (consecutive empty polls)
922
+ emptyPollCount: z.number().int().min(0).optional(),
923
+
924
+ // Last session activity timestamp (updated on tool calls, task updates, etc.)
925
+ lastActivityAt: z.iso.datetime().optional(),
926
+
927
+ // Harness provider this agent runs (claude, opencode, codex, ...)
928
+ provider: ProviderNameSchema.optional(),
929
+
930
+ // Phase 1.5 (cloud-personalization): harness provider pushed by the worker
931
+ // on registration. Mirrors `provider` but lives in its own column so the
932
+ // server can answer "what harnesses are deployed?" without joining
933
+ // anywhere else, and so an operator can re-assign via
934
+ // PATCH /api/agents/:id/harness-provider without restarting the worker.
935
+ // Worker boot path is NOT yet rewritten (DES-359 tracks that) — the
936
+ // PATCH is a planning/forecast mechanism today; on next worker restart,
937
+ // the env-driven value wins.
938
+ harnessProvider: ProviderNameSchema.nullable().optional(),
939
+
940
+ // Env-var names the worker is blocked on when status is
941
+ // `waiting_for_credentials`. Null otherwise.
942
+ credentialMissing: z.array(z.string()).nullable().optional(),
943
+
944
+ // Worker-self-reported credential snapshot for this agent's harness.
945
+ // Pairs with `harnessProvider`. Null = unreported (worker hasn't booted
946
+ // yet, or CRED_CHECK_DISABLE=1 was set). Migration 055 adds the column.
947
+ credStatus: z
948
+ .lazy(() => AgentCredStatusSchema)
949
+ .nullable()
950
+ .optional(),
951
+
952
+ // Custom avatar (icon + color). Null/missing = fall back to the
953
+ // deterministic hash-derived icon and color (see apps/ui/src/lib/agent-icon.ts
954
+ // and agent-color.ts). Migration 119 adds the column.
955
+ avatar: z
956
+ .lazy(() => AgentAvatarSchema)
957
+ .nullable()
958
+ .optional(),
959
+
960
+ // No function defaults — see AgentTaskSchema's timestamp comment
961
+ // (OpenAPI-generation reproducibility).
962
+ createdAt: z.iso.datetime(),
963
+ lastUpdatedAt: z.iso.datetime(),
964
+ })
965
+ .openapi("Agent");
909
966
 
910
967
  // ---------------------------------------------------------------------------
911
968
  // Worker-reported credential snapshot
@@ -920,23 +977,27 @@ export const AgentSchema = z.object({
920
977
  //
921
978
  // The cache-hit post-task path does NOT produce a new report; the row's
922
979
  // `reportedAt` deliberately stays at the last actual check.
923
- export const AgentCredStatusLiveTestSchema = z.object({
924
- ok: z.boolean(),
925
- error: z.string().nullable().default(null),
926
- latency_ms: z.number(),
927
- testedAt: z.number(), // unix ms
928
- });
980
+ export const AgentCredStatusLiveTestSchema = z
981
+ .object({
982
+ ok: z.boolean(),
983
+ error: z.string().nullable().default(null),
984
+ latency_ms: z.number(),
985
+ testedAt: z.number(), // unix ms
986
+ })
987
+ .openapi("AgentCredStatusLiveTest");
929
988
  export type AgentCredStatusLiveTest = z.infer<typeof AgentCredStatusLiveTestSchema>;
930
989
 
931
- export const AgentLatestModelSchema = z.object({
932
- model: z.string().min(1),
933
- source: z.enum(["task", "agent_config", "adapter_default", "custom"]),
934
- taskId: z.string().nullable().default(null),
935
- harnessProvider: ProviderNameSchema.nullable().default(null),
936
- reportedAt: z.number(), // unix ms
937
- /** Worker-applied reasoning/effort level for this session, when the adapter honored one. */
938
- reasoningEffort: ReasoningEffortSchema.optional(),
939
- });
990
+ export const AgentLatestModelSchema = z
991
+ .object({
992
+ model: z.string().min(1),
993
+ source: z.enum(["task", "agent_config", "adapter_default", "custom"]),
994
+ taskId: z.string().nullable().default(null),
995
+ harnessProvider: ProviderNameSchema.nullable().default(null),
996
+ reportedAt: z.number(), // unix ms
997
+ /** Worker-applied reasoning/effort level for this session, when the adapter honored one. */
998
+ reasoningEffort: ReasoningEffortSchema.optional(),
999
+ })
1000
+ .openapi("AgentLatestModel");
940
1001
  export type AgentLatestModel = z.infer<typeof AgentLatestModelSchema>;
941
1002
 
942
1003
  /**
@@ -949,30 +1010,34 @@ export type AgentLatestModel = z.infer<typeof AgentLatestModelSchema>;
949
1010
  * entries (e.g. OpenAI models listed in the account) are excluded. An empty
950
1011
  * `region` means Bedrock mode with `AWS_REGION` unset (no region fabricated).
951
1012
  */
952
- export const AgentBedrockStatusSchema = z.object({
953
- region: z.string(),
954
- probedAt: z.number(), // unix ms
955
- ready: z.boolean(),
956
- models: z.array(z.object({ id: z.string(), name: z.string() })).default([]),
957
- error: z.string().optional(),
958
- });
1013
+ export const AgentBedrockStatusSchema = z
1014
+ .object({
1015
+ region: z.string(),
1016
+ probedAt: z.number(), // unix ms
1017
+ ready: z.boolean(),
1018
+ models: z.array(z.object({ id: z.string(), name: z.string() })).default([]),
1019
+ error: z.string().optional(),
1020
+ })
1021
+ .openapi("AgentBedrockStatus");
959
1022
  export type AgentBedrockStatus = z.infer<typeof AgentBedrockStatusSchema>;
960
1023
 
961
- export const AgentCredStatusSchema = z.object({
962
- ready: z.boolean(),
963
- missing: z.array(z.string()).default([]),
964
- satisfiedBy: z
965
- .enum(["env", "file", "side-effect-pending", "sdk-delegated"])
966
- .nullable()
967
- .default(null),
968
- hint: z.string().nullable().default(null),
969
- liveTest: AgentCredStatusLiveTestSchema.nullable().default(null),
970
- latestModel: AgentLatestModelSchema.nullable().default(null),
971
- reportedAt: z.number(), // unix ms
972
- reportKind: z.enum(["boot", "post_task"]).default("boot"),
973
- /** Pi-mono Bedrock enumeration block — null when not in Bedrock mode. */
974
- bedrock: AgentBedrockStatusSchema.nullable().default(null),
975
- });
1024
+ export const AgentCredStatusSchema = z
1025
+ .object({
1026
+ ready: z.boolean(),
1027
+ missing: z.array(z.string()).default([]),
1028
+ satisfiedBy: z
1029
+ .enum(["env", "file", "side-effect-pending", "sdk-delegated"])
1030
+ .nullable()
1031
+ .default(null),
1032
+ hint: z.string().nullable().default(null),
1033
+ liveTest: AgentCredStatusLiveTestSchema.nullable().default(null),
1034
+ latestModel: AgentLatestModelSchema.nullable().default(null),
1035
+ reportedAt: z.number(), // unix ms
1036
+ reportKind: z.enum(["boot", "post_task"]).default("boot"),
1037
+ /** Pi-mono Bedrock enumeration block — null when not in Bedrock mode. */
1038
+ bedrock: AgentBedrockStatusSchema.nullable().default(null),
1039
+ })
1040
+ .openapi("AgentCredStatus");
976
1041
  export type AgentCredStatus = z.infer<typeof AgentCredStatusSchema>;
977
1042
 
978
1043
  export const AgentWithTasksSchema = AgentSchema.extend({
@@ -1007,19 +1072,21 @@ export const VersionableFieldSchema = z.enum([
1007
1072
  "heartbeatMd",
1008
1073
  ]);
1009
1074
 
1010
- export const ContextVersionSchema = z.object({
1011
- id: z.uuid(),
1012
- agentId: z.string(),
1013
- field: VersionableFieldSchema,
1014
- content: z.string(),
1015
- version: z.number().int().min(1),
1016
- changeSource: ChangeSourceSchema,
1017
- changedByAgentId: z.string().nullable(),
1018
- changeReason: z.string().nullable(),
1019
- contentHash: z.string(),
1020
- previousVersionId: z.uuid().nullable(),
1021
- createdAt: z.iso.datetime(),
1022
- });
1075
+ export const ContextVersionSchema = z
1076
+ .object({
1077
+ id: z.uuid(),
1078
+ agentId: z.string(),
1079
+ field: VersionableFieldSchema,
1080
+ content: z.string(),
1081
+ version: z.number().int().min(1),
1082
+ changeSource: ChangeSourceSchema,
1083
+ changedByAgentId: z.string().nullable(),
1084
+ changeReason: z.string().nullable(),
1085
+ contentHash: z.string(),
1086
+ previousVersionId: z.uuid().nullable(),
1087
+ createdAt: z.iso.datetime(),
1088
+ })
1089
+ .openapi("ContextVersion");
1023
1090
 
1024
1091
  export type ChangeSource = z.infer<typeof ChangeSourceSchema>;
1025
1092
  export type VersionableField = z.infer<typeof VersionableFieldSchema>;
@@ -1034,26 +1101,30 @@ export type VersionMeta = {
1034
1101
  // Channel Types
1035
1102
  export const ChannelTypeSchema = z.enum(["public", "dm"]);
1036
1103
 
1037
- export const ChannelSchema = z.object({
1038
- id: z.uuid(),
1039
- name: z.string().min(1).max(100),
1040
- description: z.string().max(500).optional(),
1041
- type: ChannelTypeSchema.default("public"),
1042
- createdBy: z.string().optional(),
1043
- participants: z.array(z.string()).default([]), // For DMs
1044
- createdAt: z.iso.datetime(),
1045
- });
1104
+ export const ChannelSchema = z
1105
+ .object({
1106
+ id: z.uuid(),
1107
+ name: z.string().min(1).max(100),
1108
+ description: z.string().max(500).optional(),
1109
+ type: ChannelTypeSchema.default("public"),
1110
+ createdBy: z.string().optional(),
1111
+ participants: z.array(z.string()).default([]), // For DMs
1112
+ createdAt: z.iso.datetime(),
1113
+ })
1114
+ .openapi("Channel");
1046
1115
 
1047
- export const ChannelMessageSchema = z.object({
1048
- id: z.uuid(),
1049
- channelId: z.uuid(),
1050
- agentId: z.string().nullable(), // Null for human users
1051
- agentName: z.string().optional(), // Denormalized for convenience, "Human" when agentId is null
1052
- content: z.string().min(1).max(4000),
1053
- replyToId: z.uuid().optional(),
1054
- mentions: z.array(z.string()).default([]), // Agent IDs mentioned
1055
- createdAt: z.iso.datetime(),
1056
- });
1116
+ export const ChannelMessageSchema = z
1117
+ .object({
1118
+ id: z.uuid(),
1119
+ channelId: z.uuid(),
1120
+ agentId: z.string().nullable(), // Null for human users
1121
+ agentName: z.string().optional(), // Denormalized for convenience, "Human" when agentId is null
1122
+ content: z.string().min(1).max(4000),
1123
+ replyToId: z.uuid().optional(),
1124
+ mentions: z.array(z.string()).default([]), // Agent IDs mentioned
1125
+ createdAt: z.iso.datetime(),
1126
+ })
1127
+ .openapi("ChannelMessage");
1057
1128
 
1058
1129
  export type ChannelType = z.infer<typeof ChannelTypeSchema>;
1059
1130
  export type Channel = z.infer<typeof ChannelSchema>;
@@ -1062,27 +1133,29 @@ export type ChannelMessage = z.infer<typeof ChannelMessageSchema>;
1062
1133
  // Service Types (for PM2/background services)
1063
1134
  export const ServiceStatusSchema = z.enum(["starting", "healthy", "unhealthy", "stopped"]);
1064
1135
 
1065
- export const ServiceSchema = z.object({
1066
- id: z.uuid(),
1067
- agentId: z.string(),
1068
- name: z.string().min(1).max(50),
1069
- port: z.number().int().min(1).max(65535).default(3000),
1070
- description: z.string().optional(),
1071
- url: z.string().url().optional(),
1072
- healthCheckPath: z.string().default("/health"),
1073
- status: ServiceStatusSchema.default("starting"),
1074
-
1075
- // PM2 configuration (required for ecosystem-based restart)
1076
- script: z.string().min(1), // Path to script (required)
1077
- cwd: z.string().optional(), // Working directory (defaults to script dir)
1078
- interpreter: z.string().optional(), // e.g., "node", "bun" (auto-detected if not set)
1079
- args: z.array(z.string()).optional(), // Command line arguments
1080
- env: z.record(z.string(), z.string()).optional(), // Environment variables
1081
-
1082
- metadata: z.record(z.string(), z.unknown()).default({}),
1083
- createdAt: z.iso.datetime(),
1084
- lastUpdatedAt: z.iso.datetime(),
1085
- });
1136
+ export const ServiceSchema = z
1137
+ .object({
1138
+ id: z.uuid(),
1139
+ agentId: z.string(),
1140
+ name: z.string().min(1).max(50),
1141
+ port: z.number().int().min(1).max(65535).default(3000),
1142
+ description: z.string().optional(),
1143
+ url: z.string().url().optional(),
1144
+ healthCheckPath: z.string().default("/health"),
1145
+ status: ServiceStatusSchema.default("starting"),
1146
+
1147
+ // PM2 configuration (required for ecosystem-based restart)
1148
+ script: z.string().min(1), // Path to script (required)
1149
+ cwd: z.string().optional(), // Working directory (defaults to script dir)
1150
+ interpreter: z.string().optional(), // e.g., "node", "bun" (auto-detected if not set)
1151
+ args: z.array(z.string()).optional(), // Command line arguments
1152
+ env: z.record(z.string(), z.string()).optional(), // Environment variables
1153
+
1154
+ metadata: z.record(z.string(), z.unknown()).default({}),
1155
+ createdAt: z.iso.datetime(),
1156
+ lastUpdatedAt: z.iso.datetime(),
1157
+ })
1158
+ .openapi("Service");
1086
1159
 
1087
1160
  export type ServiceStatus = z.infer<typeof ServiceStatusSchema>;
1088
1161
  export type Service = z.infer<typeof ServiceSchema>;
@@ -1128,31 +1201,35 @@ export const ResumeReasonSchema = z.enum([
1128
1201
  ]);
1129
1202
  export type ResumeReason = z.infer<typeof ResumeReasonSchema>;
1130
1203
 
1131
- export const AgentLogSchema = z.object({
1132
- id: z.uuid(),
1133
- eventType: AgentLogEventTypeSchema,
1134
- agentId: z.string().optional(),
1135
- taskId: z.string().optional(),
1136
- oldValue: z.string().optional(),
1137
- newValue: z.string().optional(),
1138
- metadata: z.string().optional(),
1139
- createdAt: z.iso.datetime(),
1140
- });
1204
+ export const AgentLogSchema = z
1205
+ .object({
1206
+ id: z.uuid(),
1207
+ eventType: AgentLogEventTypeSchema,
1208
+ agentId: z.string().optional(),
1209
+ taskId: z.string().optional(),
1210
+ oldValue: z.string().optional(),
1211
+ newValue: z.string().optional(),
1212
+ metadata: z.string().optional(),
1213
+ createdAt: z.iso.datetime(),
1214
+ })
1215
+ .openapi("AgentLog");
1141
1216
 
1142
1217
  export type AgentLogEventType = z.infer<typeof AgentLogEventTypeSchema>;
1143
1218
  export type AgentLog = z.infer<typeof AgentLogSchema>;
1144
1219
 
1145
1220
  // Session Log Types (raw CLI output)
1146
- export const SessionLogSchema = z.object({
1147
- id: z.uuid(),
1148
- taskId: z.uuid().optional(),
1149
- sessionId: z.string(),
1150
- iteration: z.number().int().min(1),
1151
- cli: z.string().default("claude"),
1152
- content: z.string(), // Raw JSON line
1153
- lineNumber: z.number().int().min(0),
1154
- createdAt: z.iso.datetime(),
1155
- });
1221
+ export const SessionLogSchema = z
1222
+ .object({
1223
+ id: z.uuid(),
1224
+ taskId: z.uuid().optional(),
1225
+ sessionId: z.string(),
1226
+ iteration: z.number().int().min(1),
1227
+ cli: z.string().default("claude"),
1228
+ content: z.string(), // Raw JSON line
1229
+ lineNumber: z.number().int().min(0),
1230
+ createdAt: z.iso.datetime(),
1231
+ })
1232
+ .openapi("SessionLog");
1156
1233
 
1157
1234
  export type SessionLog = z.infer<typeof SessionLogSchema>;
1158
1235
 
@@ -1162,52 +1239,56 @@ export type SessionLog = z.infer<typeof SessionLogSchema>;
1162
1239
  export const SessionCostSourceSchema = z.enum(["harness", "pricing-table", "unpriced"]);
1163
1240
  export type SessionCostSource = z.infer<typeof SessionCostSourceSchema>;
1164
1241
 
1165
- export const SessionCostModelBreakdownSchema = z.object({
1166
- model: z.string(),
1167
- inputTokens: z.number().int().nonnegative(),
1168
- outputTokens: z.number().int().nonnegative(),
1169
- cacheReadTokens: z.number().int().nonnegative(),
1170
- cacheWriteTokens: z.number().int().nonnegative(),
1171
- webSearchRequests: z.number().int().nonnegative().nullable().optional(),
1172
- costUsd: z.number().nullable().optional(),
1173
- harnessCostUsd: z.number().nullable().optional(),
1174
- });
1242
+ export const SessionCostModelBreakdownSchema = z
1243
+ .object({
1244
+ model: z.string(),
1245
+ inputTokens: z.number().int().nonnegative(),
1246
+ outputTokens: z.number().int().nonnegative(),
1247
+ cacheReadTokens: z.number().int().nonnegative(),
1248
+ cacheWriteTokens: z.number().int().nonnegative(),
1249
+ webSearchRequests: z.number().int().nonnegative().nullable().optional(),
1250
+ costUsd: z.number().nullable().optional(),
1251
+ harnessCostUsd: z.number().nullable().optional(),
1252
+ })
1253
+ .openapi("SessionCostModelBreakdown");
1175
1254
  export type SessionCostModelBreakdown = z.infer<typeof SessionCostModelBreakdownSchema>;
1176
1255
 
1177
- export const SessionCostSchema = z.object({
1178
- id: z.uuid(),
1179
- sessionId: z.string(),
1180
- taskId: z.uuid().optional(),
1181
- agentId: z.string(),
1182
- totalCostUsd: z.number().min(0),
1183
- inputTokens: z.number().int().min(0).default(0),
1184
- outputTokens: z.number().int().min(0).default(0),
1185
- cacheReadTokens: z.number().int().min(0).default(0),
1186
- cacheWriteTokens: z.number().int().min(0).default(0),
1187
- // Migration 063: reasoning_output_tokens from codex turn.completed events.
1188
- reasoningOutputTokens: z.number().int().min(0).default(0),
1189
- // Migration 063: thinking_input_tokens from claude extended-thinking flows.
1190
- thinkingTokens: z.number().int().min(0).default(0),
1191
- durationMs: z.number().int().min(0),
1192
- // numTurns is nullable — some adapters (e.g. Claude when num_turns is absent)
1193
- // can't honestly report a turn count. We prefer null over a faked 1.
1194
- numTurns: z.number().int().min(1).nullable(),
1195
- model: z.string(),
1196
- isError: z.boolean().default(false),
1197
- // Phase 6 (extended by migration 063): where the recorded totalCostUsd came from.
1198
- // 'harness' — value reported by the harness as-is.
1199
- // 'pricing-table' — value recomputed by the API from `pricing` rows.
1200
- // 'unpriced' — the API tried to recompute but the (provider, model)
1201
- // had no matching pricing rows; totalCostUsd is whatever
1202
- // the worker submitted (often 0).
1203
- costSource: SessionCostSourceSchema.default("harness"),
1204
- // Migration 128: adapter-reported amount retained for reconciliation only.
1205
- harnessCostUsd: z.number().nullable().optional(),
1206
- cacheWrite5mTokens: z.number().int().nullable().optional(),
1207
- cacheWrite1hTokens: z.number().int().nullable().optional(),
1208
- modelBreakdown: z.array(SessionCostModelBreakdownSchema).nullable().optional(),
1209
- createdAt: z.iso.datetime(),
1210
- });
1256
+ export const SessionCostSchema = z
1257
+ .object({
1258
+ id: z.uuid(),
1259
+ sessionId: z.string(),
1260
+ taskId: z.uuid().optional(),
1261
+ agentId: z.string(),
1262
+ totalCostUsd: z.number().min(0),
1263
+ inputTokens: z.number().int().min(0).default(0),
1264
+ outputTokens: z.number().int().min(0).default(0),
1265
+ cacheReadTokens: z.number().int().min(0).default(0),
1266
+ cacheWriteTokens: z.number().int().min(0).default(0),
1267
+ // Migration 063: reasoning_output_tokens from codex turn.completed events.
1268
+ reasoningOutputTokens: z.number().int().min(0).default(0),
1269
+ // Migration 063: thinking_input_tokens from claude extended-thinking flows.
1270
+ thinkingTokens: z.number().int().min(0).default(0),
1271
+ durationMs: z.number().int().min(0),
1272
+ // numTurns is nullable — some adapters (e.g. Claude when num_turns is absent)
1273
+ // can't honestly report a turn count. We prefer null over a faked 1.
1274
+ numTurns: z.number().int().min(1).nullable(),
1275
+ model: z.string(),
1276
+ isError: z.boolean().default(false),
1277
+ // Phase 6 (extended by migration 063): where the recorded totalCostUsd came from.
1278
+ // 'harness' — value reported by the harness as-is.
1279
+ // 'pricing-table' — value recomputed by the API from `pricing` rows.
1280
+ // 'unpriced' — the API tried to recompute but the (provider, model)
1281
+ // had no matching pricing rows; totalCostUsd is whatever
1282
+ // the worker submitted (often 0).
1283
+ costSource: SessionCostSourceSchema.default("harness"),
1284
+ // Migration 128: adapter-reported amount retained for reconciliation only.
1285
+ harnessCostUsd: z.number().nullable().optional(),
1286
+ cacheWrite5mTokens: z.number().int().nullable().optional(),
1287
+ cacheWrite1hTokens: z.number().int().nullable().optional(),
1288
+ modelBreakdown: z.array(SessionCostModelBreakdownSchema).nullable().optional(),
1289
+ createdAt: z.iso.datetime(),
1290
+ })
1291
+ .openapi("SessionCost");
1211
1292
 
1212
1293
  export type SessionCost = z.infer<typeof SessionCostSchema>;
1213
1294
 
@@ -1263,21 +1344,23 @@ export const EventNameSchema = z.enum([
1263
1344
  "schedule.deleted",
1264
1345
  ]);
1265
1346
 
1266
- export const SwarmEventSchema = z.object({
1267
- id: z.uuid(),
1268
- category: EventCategorySchema,
1269
- event: EventNameSchema,
1270
- status: EventStatusSchema,
1271
- source: EventSourceSchema,
1272
- agentId: z.string().optional(),
1273
- taskId: z.string().optional(),
1274
- sessionId: z.string().optional(),
1275
- parentEventId: z.string().optional(),
1276
- numericValue: z.number().optional(),
1277
- durationMs: z.number().int().optional(),
1278
- data: z.record(z.string(), z.unknown()).optional(),
1279
- createdAt: z.iso.datetime(),
1280
- });
1347
+ export const SwarmEventSchema = z
1348
+ .object({
1349
+ id: z.uuid(),
1350
+ category: EventCategorySchema,
1351
+ event: EventNameSchema,
1352
+ status: EventStatusSchema,
1353
+ source: EventSourceSchema,
1354
+ agentId: z.string().optional(),
1355
+ taskId: z.string().optional(),
1356
+ sessionId: z.string().optional(),
1357
+ parentEventId: z.string().optional(),
1358
+ numericValue: z.number().optional(),
1359
+ durationMs: z.number().int().optional(),
1360
+ data: z.record(z.string(), z.unknown()).optional(),
1361
+ createdAt: z.iso.datetime(),
1362
+ })
1363
+ .openapi("SwarmEvent");
1281
1364
 
1282
1365
  export type EventCategory = z.infer<typeof EventCategorySchema>;
1283
1366
  export type EventStatus = z.infer<typeof EventStatusSchema>;
@@ -1361,23 +1444,25 @@ export type ScheduledTask = z.infer<typeof ScheduledTaskSchema>;
1361
1444
 
1362
1445
  export const SwarmConfigScopeSchema = z.enum(["global", "agent", "repo"]);
1363
1446
 
1364
- export const SwarmConfigSchema = z.object({
1365
- id: z.string().uuid(),
1366
- scope: SwarmConfigScopeSchema,
1367
- scopeId: z.string().nullable(), // agentId or repoId, null for global
1368
- key: z.string().min(1).max(255),
1369
- value: z.string(),
1370
- isSecret: z.boolean(),
1371
- envPath: z.string().nullable(),
1372
- description: z.string().nullable(),
1373
- createdAt: z.string(),
1374
- lastUpdatedAt: z.string(),
1375
- // True when the row's value is stored as AES-256-GCM ciphertext in the DB.
1376
- // Plaintext rows return encrypted=false. Legacy isSecret=1 rows are
1377
- // auto-encrypted during initDb; if that fails, boot aborts before normal API
1378
- // reads occur.
1379
- encrypted: z.boolean(),
1380
- });
1447
+ export const SwarmConfigSchema = z
1448
+ .object({
1449
+ id: z.string().uuid(),
1450
+ scope: SwarmConfigScopeSchema,
1451
+ scopeId: z.string().nullable(), // agentId or repoId, null for global
1452
+ key: z.string().min(1).max(255),
1453
+ value: z.string(),
1454
+ isSecret: z.boolean(),
1455
+ envPath: z.string().nullable(),
1456
+ description: z.string().nullable(),
1457
+ createdAt: z.string(),
1458
+ lastUpdatedAt: z.string(),
1459
+ // True when the row's value is stored as AES-256-GCM ciphertext in the DB.
1460
+ // Plaintext rows return encrypted=false. Legacy isSecret=1 rows are
1461
+ // auto-encrypted during initDb; if that fails, boot aborts before normal API
1462
+ // reads occur.
1463
+ encrypted: z.boolean(),
1464
+ })
1465
+ .openapi("SwarmConfig");
1381
1466
 
1382
1467
  export type SwarmConfigScope = z.infer<typeof SwarmConfigScopeSchema>;
1383
1468
  export type SwarmConfig = z.infer<typeof SwarmConfigSchema>;
@@ -1386,33 +1471,39 @@ export type SwarmConfig = z.infer<typeof SwarmConfigSchema>;
1386
1471
  // Swarm Repos Types (Centralized Repository Management)
1387
1472
  // ============================================================================
1388
1473
 
1389
- export const RepoGuidelinesSchema = z.object({
1390
- prChecks: z.array(z.string()),
1391
- mergeChecks: z.array(z.string()),
1392
- allowMerge: z.boolean().optional().default(false),
1393
- review: z.array(z.string()),
1394
- });
1474
+ export const RepoGuidelinesSchema = z
1475
+ .object({
1476
+ prChecks: z.array(z.string()),
1477
+ mergeChecks: z.array(z.string()),
1478
+ allowMerge: z.boolean().optional().default(false),
1479
+ review: z.array(z.string()),
1480
+ })
1481
+ .openapi("RepoGuidelines");
1395
1482
 
1396
1483
  export type RepoGuidelines = z.infer<typeof RepoGuidelinesSchema>;
1397
1484
 
1398
- export const RepoHooksSchema = z.object({
1399
- enabled: z.boolean().default(false),
1400
- });
1485
+ export const RepoHooksSchema = z
1486
+ .object({
1487
+ enabled: z.boolean().default(false),
1488
+ })
1489
+ .openapi("RepoHooks");
1401
1490
 
1402
1491
  export type RepoHooks = z.infer<typeof RepoHooksSchema>;
1403
1492
 
1404
- export const SwarmRepoSchema = z.object({
1405
- id: z.string().uuid(),
1406
- url: z.string().min(1),
1407
- name: z.string().min(1).max(100),
1408
- clonePath: z.string().min(1),
1409
- defaultBranch: z.string().default("main"),
1410
- autoClone: z.boolean().default(true),
1411
- hooks: RepoHooksSchema.optional().default({ enabled: false }),
1412
- guidelines: RepoGuidelinesSchema.nullable().optional(),
1413
- createdAt: z.string(),
1414
- lastUpdatedAt: z.string(),
1415
- });
1493
+ export const SwarmRepoSchema = z
1494
+ .object({
1495
+ id: z.string().uuid(),
1496
+ url: z.string().min(1),
1497
+ name: z.string().min(1).max(100),
1498
+ clonePath: z.string().min(1),
1499
+ defaultBranch: z.string().default("main"),
1500
+ autoClone: z.boolean().default(true),
1501
+ hooks: RepoHooksSchema.optional().default({ enabled: false }),
1502
+ guidelines: RepoGuidelinesSchema.nullable().optional(),
1503
+ createdAt: z.string(),
1504
+ lastUpdatedAt: z.string(),
1505
+ })
1506
+ .openapi("SwarmRepo");
1416
1507
 
1417
1508
  export type SwarmRepo = z.infer<typeof SwarmRepoSchema>;
1418
1509
 
@@ -1428,29 +1519,31 @@ export const AgentMemorySourceSchema = z.enum([
1428
1519
  "task_completion",
1429
1520
  ]);
1430
1521
 
1431
- export const AgentMemorySchema = z.object({
1432
- id: z.string().uuid(),
1433
- agentId: z.string().nullable(),
1434
- scope: AgentMemoryScopeSchema,
1435
- key: z.string().nullable().optional(),
1436
- name: z.string().min(1).max(500),
1437
- content: z.string(),
1438
- summary: z.string().nullable(),
1439
- source: AgentMemorySourceSchema,
1440
- sourceTaskId: z.string().uuid().nullable(),
1441
- sourcePath: z.string().nullable(),
1442
- chunkIndex: z.number().int().min(0).default(0),
1443
- totalChunks: z.number().int().min(1).default(1),
1444
- tags: z.array(z.string()),
1445
- createdAt: z.string(),
1446
- updatedAt: z.string().nullable().optional(),
1447
- accessedAt: z.string(),
1448
- expiresAt: z.string().nullable().optional(),
1449
- accessCount: z.number().int().min(0).default(0).optional(),
1450
- embeddingModel: z.string().nullable().optional(),
1451
- contentHash: z.string().nullable().optional(),
1452
- version: z.number().int().min(1).default(1).optional(),
1453
- });
1522
+ export const AgentMemorySchema = z
1523
+ .object({
1524
+ id: z.string().uuid(),
1525
+ agentId: z.string().nullable(),
1526
+ scope: AgentMemoryScopeSchema,
1527
+ key: z.string().nullable().optional(),
1528
+ name: z.string().min(1).max(500),
1529
+ content: z.string(),
1530
+ summary: z.string().nullable(),
1531
+ source: AgentMemorySourceSchema,
1532
+ sourceTaskId: z.string().uuid().nullable(),
1533
+ sourcePath: z.string().nullable(),
1534
+ chunkIndex: z.number().int().min(0).default(0),
1535
+ totalChunks: z.number().int().min(1).default(1),
1536
+ tags: z.array(z.string()),
1537
+ createdAt: z.string(),
1538
+ updatedAt: z.string().nullable().optional(),
1539
+ accessedAt: z.string(),
1540
+ expiresAt: z.string().nullable().optional(),
1541
+ accessCount: z.number().int().min(0).default(0).optional(),
1542
+ embeddingModel: z.string().nullable().optional(),
1543
+ contentHash: z.string().nullable().optional(),
1544
+ version: z.number().int().min(1).default(1).optional(),
1545
+ })
1546
+ .openapi("AgentMemory");
1454
1547
 
1455
1548
  export type AgentMemoryScope = z.infer<typeof AgentMemoryScopeSchema>;
1456
1549
  export type AgentMemorySource = z.infer<typeof AgentMemorySourceSchema>;
@@ -1460,18 +1553,20 @@ export type AgentMemory = z.infer<typeof AgentMemorySchema>;
1460
1553
  // Active Session Types (runner session tracking)
1461
1554
  // ============================================================================
1462
1555
 
1463
- export const ActiveSessionSchema = z.object({
1464
- id: z.uuid(),
1465
- agentId: z.string(),
1466
- taskId: z.string().nullable(),
1467
- triggerType: z.string(),
1468
- inboxMessageId: z.string().nullable(),
1469
- taskDescription: z.string().nullable(),
1470
- runnerSessionId: z.string().nullable(),
1471
- providerSessionId: z.string().nullable(),
1472
- startedAt: z.iso.datetime(),
1473
- lastHeartbeatAt: z.iso.datetime(),
1474
- });
1556
+ export const ActiveSessionSchema = z
1557
+ .object({
1558
+ id: z.uuid(),
1559
+ agentId: z.string(),
1560
+ taskId: z.string().nullable(),
1561
+ triggerType: z.string(),
1562
+ inboxMessageId: z.string().nullable(),
1563
+ taskDescription: z.string().nullable(),
1564
+ runnerSessionId: z.string().nullable(),
1565
+ providerSessionId: z.string().nullable(),
1566
+ startedAt: z.iso.datetime(),
1567
+ lastHeartbeatAt: z.iso.datetime(),
1568
+ })
1569
+ .openapi("ActiveSession");
1475
1570
 
1476
1571
  export type ActiveSession = z.infer<typeof ActiveSessionSchema>;
1477
1572
 
@@ -1481,133 +1576,154 @@ export type ActiveSession = z.infer<typeof ActiveSessionSchema>;
1481
1576
 
1482
1577
  // --- Retry Policy ---
1483
1578
 
1484
- export const RetryPolicySchema = z.object({
1485
- maxRetries: z.number().int().min(0).default(3),
1486
- strategy: z.enum(["exponential", "static", "linear"]).default("exponential"),
1487
- baseDelayMs: z.number().int().min(0).default(1000),
1488
- maxDelayMs: z.number().int().min(0).default(60000),
1489
- });
1579
+ export const RetryPolicySchema = z
1580
+ .object({
1581
+ maxRetries: z.number().int().min(0).default(3),
1582
+ strategy: z.enum(["exponential", "static", "linear"]).default("exponential"),
1583
+ baseDelayMs: z.number().int().min(0).default(1000),
1584
+ maxDelayMs: z.number().int().min(0).default(60000),
1585
+ })
1586
+ .openapi("RetryPolicy");
1490
1587
  export type RetryPolicy = z.infer<typeof RetryPolicySchema>;
1491
1588
 
1492
1589
  // --- Executor Metadata ---
1493
1590
 
1494
- export const ExecutorMetaSchema = z.object({
1495
- runId: z.string().uuid(),
1496
- stepId: z.string().uuid(),
1497
- nodeId: z.string(),
1498
- workflowId: z.string().uuid(),
1499
- dryRun: z.boolean().default(false),
1500
- requestedByUserId: z.string().optional(),
1501
- // The node's declared-inputs interpolation context (aliases + builtins) as built
1502
- // by buildNodeInterpolationCtx. Executors that defer interpolation (foreach's
1503
- // per-item body pass) must use THIS — not the full run context — so deferred
1504
- // config obeys the same explicit-dataflow boundary as normal node config.
1505
- inputCtx: z.record(z.string(), z.unknown()).optional(),
1506
- });
1591
+ export const ExecutorMetaSchema = z
1592
+ .object({
1593
+ runId: z.string().uuid(),
1594
+ stepId: z.string().uuid(),
1595
+ nodeId: z.string(),
1596
+ workflowId: z.string().uuid(),
1597
+ dryRun: z.boolean().default(false),
1598
+ requestedByUserId: z.string().optional(),
1599
+ // The node's declared-inputs interpolation context (aliases + builtins) as built
1600
+ // by buildNodeInterpolationCtx. Executors that defer interpolation (foreach's
1601
+ // per-item body pass) must use THIS — not the full run context — so deferred
1602
+ // config obeys the same explicit-dataflow boundary as normal node config.
1603
+ inputCtx: z.record(z.string(), z.unknown()).optional(),
1604
+ })
1605
+ .openapi("ExecutorMeta");
1507
1606
  export type ExecutorMeta = z.infer<typeof ExecutorMetaSchema>;
1508
1607
 
1509
1608
  // --- Validation ---
1510
1609
 
1511
- export const ValidationResultSchema = z.object({
1512
- pass: z.boolean(),
1513
- reasoning: z.string(),
1514
- confidence: z.number().min(0).max(1),
1515
- });
1610
+ export const ValidationResultSchema = z
1611
+ .object({
1612
+ pass: z.boolean(),
1613
+ reasoning: z.string(),
1614
+ confidence: z.number().min(0).max(1),
1615
+ })
1616
+ .openapi("ValidationResult");
1516
1617
  export type ValidationResult = z.infer<typeof ValidationResultSchema>;
1517
1618
 
1518
- export const StepValidationConfigSchema = z.object({
1519
- executor: z.string().default("validate"),
1520
- config: z.record(z.string(), z.unknown()),
1521
- mustPass: z.boolean().default(false),
1522
- retry: RetryPolicySchema.optional(),
1523
- });
1619
+ export const StepValidationConfigSchema = z
1620
+ .object({
1621
+ executor: z.string().default("validate"),
1622
+ config: z.record(z.string(), z.unknown()),
1623
+ mustPass: z.boolean().default(false),
1624
+ retry: RetryPolicySchema.optional(),
1625
+ })
1626
+ .openapi("StepValidationConfig");
1524
1627
  export type StepValidationConfig = z.infer<typeof StepValidationConfigSchema>;
1525
1628
 
1526
- export const SwarmScriptNodeConfigSchema = z.object({
1527
- scriptName: z.string().min(1),
1528
- scope: z.enum(["global", "agent"]).optional(),
1529
- pinHash: z.string().min(1).optional(),
1530
- args: z.record(z.string(), z.unknown()).optional(),
1531
- fsMode: z.enum(["none", "workspace-rw"]).optional(),
1532
- timeoutMs: z.number().int().min(1_000).max(300_000).optional(),
1533
- });
1629
+ export const SwarmScriptNodeConfigSchema = z
1630
+ .object({
1631
+ scriptName: z.string().min(1),
1632
+ scope: z.enum(["global", "agent"]).optional(),
1633
+ pinHash: z.string().min(1).optional(),
1634
+ args: z.record(z.string(), z.unknown()).optional(),
1635
+ fsMode: z.enum(["none", "workspace-rw"]).optional(),
1636
+ timeoutMs: z.number().int().min(1_000).max(300_000).optional(),
1637
+ })
1638
+ .openapi("SwarmScriptNodeConfig");
1534
1639
  export type SwarmScriptNodeConfig = z.infer<typeof SwarmScriptNodeConfigSchema>;
1535
1640
 
1536
1641
  // --- Workflow Node (nodes-with-next) ---
1537
1642
 
1538
- export const WorkflowNodeSchema = z.object({
1539
- id: z.string().describe("Unique node identifier, used in 'next' and 'inputs' mappings"),
1540
- type: z
1541
- .string()
1542
- .describe(
1543
- "Executor type: 'agent-task', 'script', 'swarm-script', 'raw-llm', 'validate', 'property-match'",
1544
- ),
1545
- label: z.string().optional().describe("Human-readable label for UI display"),
1546
- config: z
1547
- .record(z.string(), z.unknown())
1548
- .describe(
1549
- "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. " +
1550
- "For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. " +
1551
- "Values support {{interpolation}} from the node's inputs context. " +
1552
- "NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, " +
1553
- "while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput}).",
1554
- ),
1555
- next: z
1556
- .union([z.string(), z.array(z.string()), z.record(z.string(), z.string())])
1557
- .optional()
1558
- .describe(
1559
- "Next node(s): string for simple chaining, string[] for fan-out to parallel nodes, or record for port-based routing ({pass: 'a', fail: 'b'})",
1560
- ),
1561
- validation: StepValidationConfigSchema.optional(),
1562
- retry: RetryPolicySchema.optional(),
1563
- // REQUIRED for cross-node data access — without this, only 'trigger' and 'input' are available for interpolation.
1564
- inputs: z
1565
- .record(z.string(), z.string())
1566
- .optional()
1567
- .describe(
1568
- "REQUIRED for cross-node data access. Maps local names to context paths. " +
1569
- "Without this, upstream step outputs are NOT available for interpolation — only 'trigger' and 'input' are. " +
1570
- 'Example: { "cityData": "generate-city" } → use {{cityData.taskOutput.field}} in config templates. ' +
1571
- 'For trigger data: { "pr": "trigger.pullRequest" }.',
1572
- ),
1573
- inputSchema: z
1574
- .record(z.string(), z.unknown())
1575
- .optional()
1576
- .describe("JSON Schema to validate resolved inputs before execution"),
1577
- outputSchema: z
1578
- .record(z.string(), z.unknown())
1579
- .optional()
1580
- .describe(
1581
- "JSON Schema to validate the executor's output (e.g. {taskId, taskOutput} for agent-task). " +
1582
- "Different from config.outputSchema which validates the agent's raw output.",
1583
- ),
1584
- });
1643
+ export const WorkflowNodeSchema = z
1644
+ .object({
1645
+ id: z.string().describe("Unique node identifier, used in 'next' and 'inputs' mappings"),
1646
+ type: z
1647
+ .string()
1648
+ .describe(
1649
+ "Executor type: 'agent-task', 'script', 'swarm-script', 'raw-llm', 'validate', 'property-match'",
1650
+ ),
1651
+ label: z.string().optional().describe("Human-readable label for UI display"),
1652
+ config: z
1653
+ .record(z.string(), z.unknown())
1654
+ .describe(
1655
+ "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. " +
1656
+ "For script: { runtime, script, args?, timeout? }. " +
1657
+ "For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. " +
1658
+ "Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. " +
1659
+ "SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. " +
1660
+ "Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). " +
1661
+ "NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, " +
1662
+ "while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput}).",
1663
+ ),
1664
+ next: z
1665
+ .union([z.string(), z.array(z.string()), z.record(z.string(), z.string())])
1666
+ .optional()
1667
+ .describe(
1668
+ "Next node(s): string for simple chaining, string[] for fan-out to parallel nodes, or record for port-based routing ({pass: 'a', fail: 'b'})",
1669
+ ),
1670
+ validation: StepValidationConfigSchema.optional(),
1671
+ retry: RetryPolicySchema.optional(),
1672
+ // REQUIRED for cross-node data access; built-in context roots remain available without aliases.
1673
+ inputs: z
1674
+ .record(z.string(), z.string())
1675
+ .optional()
1676
+ .describe(
1677
+ "REQUIRED for cross-node data access. Maps local names to context paths. " +
1678
+ "Without this, upstream step outputs are NOT available for interpolation; built-in trigger/input/workflow/swarm/run context remains available. " +
1679
+ 'Example: { "cityData": "generate-city" } → use {{cityData.taskOutput.field}} in config templates. ' +
1680
+ 'For trigger data: { "pr": "trigger.pullRequest" }. ' +
1681
+ "This mapping works in agent-task templates and ordinary config, but executable script/swarm-script source excludes trigger and upstream-output aliases. " +
1682
+ "Route those dynamic values through config.args (argv for inline scripts) instead.",
1683
+ ),
1684
+ inputSchema: z
1685
+ .record(z.string(), z.unknown())
1686
+ .optional()
1687
+ .describe("JSON Schema to validate resolved inputs before execution"),
1688
+ outputSchema: z
1689
+ .record(z.string(), z.unknown())
1690
+ .optional()
1691
+ .describe(
1692
+ "JSON Schema to validate the executor's output (e.g. {taskId, taskOutput} for agent-task). " +
1693
+ "Different from config.outputSchema which validates the agent's raw output.",
1694
+ ),
1695
+ })
1696
+ .openapi("WorkflowNode");
1585
1697
  export type WorkflowNode = z.infer<typeof WorkflowNodeSchema>;
1586
1698
 
1587
1699
  // --- Workflow Edge (derived — for UI rendering) ---
1588
1700
 
1589
- export const WorkflowEdgeSchema = z.object({
1590
- id: z.string(),
1591
- source: z.string(),
1592
- sourcePort: z.string(),
1593
- target: z.string(),
1594
- });
1701
+ export const WorkflowEdgeSchema = z
1702
+ .object({
1703
+ id: z.string(),
1704
+ source: z.string(),
1705
+ sourcePort: z.string(),
1706
+ target: z.string(),
1707
+ })
1708
+ .openapi("WorkflowEdge");
1595
1709
  export type WorkflowEdge = z.infer<typeof WorkflowEdgeSchema>;
1596
1710
 
1597
1711
  // --- Workflow Definition (nodes-only, no explicit edges) ---
1598
1712
 
1599
- export const WorkflowDefinitionSchema = z.object({
1600
- nodes: z.array(WorkflowNodeSchema).min(1),
1601
- onNodeFailure: z
1602
- .enum(["fail", "continue"])
1603
- .default("fail")
1604
- .describe(
1605
- "Behavior when a node's task fails or is cancelled. " +
1606
- "'fail' (default): mark the entire run as failed. " +
1607
- "'continue': treat the failed node as completed with error output and proceed — " +
1608
- "downstream convergence nodes receive '[FAILED: reason]' and can handle partial results.",
1609
- ),
1610
- });
1713
+ export const WorkflowDefinitionSchema = z
1714
+ .object({
1715
+ nodes: z.array(WorkflowNodeSchema).min(1),
1716
+ onNodeFailure: z
1717
+ .enum(["fail", "continue"])
1718
+ .default("fail")
1719
+ .describe(
1720
+ "Behavior when a node's task fails or is cancelled. " +
1721
+ "'fail' (default): mark the entire run as failed. " +
1722
+ "'continue': treat the failed node as completed with error output and proceed — " +
1723
+ "downstream convergence nodes receive '[FAILED: reason]' and can handle partial results.",
1724
+ ),
1725
+ })
1726
+ .openapi("WorkflowDefinition");
1611
1727
  export type WorkflowDefinition = z.infer<typeof WorkflowDefinitionSchema>;
1612
1728
 
1613
1729
  // --- Workflow Patch Schemas ---
@@ -1617,33 +1733,35 @@ export const WorkflowNodePatchSchema = WorkflowNodeSchema.partial().omit({ id: t
1617
1733
  export type WorkflowNodePatch = z.infer<typeof WorkflowNodePatchSchema>;
1618
1734
 
1619
1735
  /** Bulk workflow patch — DAG operations plus optional metadata fields like triggerSchema */
1620
- export const WorkflowPatchSchema = z.object({
1621
- update: z
1622
- .array(
1623
- z.object({
1624
- nodeId: z.string().describe("ID of the node to update"),
1625
- node: WorkflowNodePatchSchema.describe("Partial node data to merge"),
1626
- }),
1627
- )
1628
- .optional()
1629
- .describe("Nodes to update (partial merge)"),
1630
- delete: z.array(z.string()).optional().describe("Node IDs to delete"),
1631
- create: z.array(WorkflowNodeSchema).optional().describe("New nodes to add"),
1632
- onNodeFailure: z
1633
- .enum(["fail", "continue"])
1634
- .optional()
1635
- .describe("Update the definition-level onNodeFailure behavior"),
1636
- triggerSchema: z
1637
- .record(z.string(), z.unknown())
1638
- .optional()
1639
- .nullable()
1640
- .describe(
1641
- "Optional JSON-Schema describing the expected trigger payload shape. " +
1642
- "Pass an object to set/replace; pass null to clear; omit to leave unchanged. " +
1643
- "Validator subset: type, required, properties, enum, const, items. " +
1644
- "Other JSON-Schema keywords are silently ignored.",
1645
- ),
1646
- });
1736
+ export const WorkflowPatchSchema = z
1737
+ .object({
1738
+ update: z
1739
+ .array(
1740
+ z.object({
1741
+ nodeId: z.string().describe("ID of the node to update"),
1742
+ node: WorkflowNodePatchSchema.describe("Partial node data to merge"),
1743
+ }),
1744
+ )
1745
+ .optional()
1746
+ .describe("Nodes to update (partial merge)"),
1747
+ delete: z.array(z.string()).optional().describe("Node IDs to delete"),
1748
+ create: z.array(WorkflowNodeSchema).optional().describe("New nodes to add"),
1749
+ onNodeFailure: z
1750
+ .enum(["fail", "continue"])
1751
+ .optional()
1752
+ .describe("Update the definition-level onNodeFailure behavior"),
1753
+ triggerSchema: z
1754
+ .record(z.string(), z.unknown())
1755
+ .optional()
1756
+ .nullable()
1757
+ .describe(
1758
+ "Optional JSON-Schema describing the expected trigger payload shape. " +
1759
+ "Pass an object to set/replace; pass null to clear; omit to leave unchanged. " +
1760
+ "Validator subset: type, required, properties, enum, const, items. " +
1761
+ "Other JSON-Schema keywords are silently ignored.",
1762
+ ),
1763
+ })
1764
+ .openapi("WorkflowPatch");
1647
1765
  export type WorkflowPatch = z.infer<typeof WorkflowPatchSchema>;
1648
1766
 
1649
1767
  /** Result of applying a patch — collects all errors instead of throwing on the first */
@@ -1752,74 +1870,82 @@ export type InputValue = z.infer<typeof InputValueSchema>;
1752
1870
 
1753
1871
  // --- Workflow Template ---
1754
1872
 
1755
- export const WorkflowTemplateSchema = z.object({
1756
- id: z.string().uuid(),
1757
- name: z.string(),
1758
- description: z.string(),
1759
- category: z.string(),
1760
- variables: z.array(
1761
- z.object({
1762
- name: z.string(),
1763
- description: z.string(),
1764
- type: z.enum(["string", "number", "boolean"]),
1765
- default: z.unknown().optional(),
1766
- required: z.boolean().default(true),
1767
- }),
1768
- ),
1769
- definition: WorkflowDefinitionSchema,
1770
- });
1873
+ export const WorkflowTemplateSchema = z
1874
+ .object({
1875
+ id: z.string().uuid(),
1876
+ name: z.string(),
1877
+ description: z.string(),
1878
+ category: z.string(),
1879
+ variables: z.array(
1880
+ z.object({
1881
+ name: z.string(),
1882
+ description: z.string(),
1883
+ type: z.enum(["string", "number", "boolean"]),
1884
+ default: z.unknown().optional(),
1885
+ required: z.boolean().default(true),
1886
+ }),
1887
+ ),
1888
+ definition: WorkflowDefinitionSchema,
1889
+ })
1890
+ .openapi("WorkflowTemplate");
1771
1891
  export type WorkflowTemplate = z.infer<typeof WorkflowTemplateSchema>;
1772
1892
 
1773
1893
  // --- Workflow Snapshot (for version history) ---
1774
1894
 
1775
- export const WorkflowSnapshotSchema = z.object({
1776
- name: z.string(),
1777
- description: z.string().optional(),
1778
- definition: WorkflowDefinitionSchema,
1779
- triggers: z.array(TriggerConfigSchema),
1780
- cooldown: CooldownConfigSchema.optional(),
1781
- input: z.record(z.string(), InputValueSchema).optional(),
1782
- triggerSchema: z.record(z.string(), z.unknown()).optional(),
1783
- dir: z.string().min(1).startsWith("/").optional(),
1784
- vcsRepo: z.string().min(1).optional(),
1785
- enabled: z.boolean(),
1786
- });
1895
+ export const WorkflowSnapshotSchema = z
1896
+ .object({
1897
+ name: z.string(),
1898
+ description: z.string().optional(),
1899
+ definition: WorkflowDefinitionSchema,
1900
+ triggers: z.array(TriggerConfigSchema),
1901
+ cooldown: CooldownConfigSchema.optional(),
1902
+ input: z.record(z.string(), InputValueSchema).optional(),
1903
+ triggerSchema: z.record(z.string(), z.unknown()).optional(),
1904
+ dir: z.string().min(1).startsWith("/").optional(),
1905
+ vcsRepo: z.string().min(1).optional(),
1906
+ enabled: z.boolean(),
1907
+ })
1908
+ .openapi("WorkflowSnapshot");
1787
1909
  export type WorkflowSnapshot = z.infer<typeof WorkflowSnapshotSchema>;
1788
1910
 
1789
1911
  // --- Workflow ---
1790
1912
 
1791
- export const WorkflowSchema = z.object({
1792
- id: z.string().uuid(),
1793
- key: AssetKeySchema,
1794
- name: z.string(),
1795
- description: z.string().optional(),
1796
- enabled: z.boolean(),
1797
- definition: WorkflowDefinitionSchema,
1798
- triggers: z.array(TriggerConfigSchema).default([]),
1799
- cooldown: CooldownConfigSchema.optional(),
1800
- input: z.record(z.string(), InputValueSchema).optional(),
1801
- triggerSchema: z.record(z.string(), z.unknown()).optional(),
1802
- dir: z.string().min(1).startsWith("/").optional(),
1803
- vcsRepo: z.string().min(1).optional(),
1804
- createdByAgentId: z.string().optional(),
1805
- createdAt: z.string(),
1806
- lastUpdatedAt: z.string(),
1807
- createdBy: z.string().optional(),
1808
- updatedBy: z.string().optional(),
1809
- favorite: z.boolean().optional(),
1810
- });
1913
+ export const WorkflowSchema = z
1914
+ .object({
1915
+ id: z.string().uuid(),
1916
+ key: AssetKeySchema,
1917
+ name: z.string(),
1918
+ description: z.string().optional(),
1919
+ enabled: z.boolean(),
1920
+ definition: WorkflowDefinitionSchema,
1921
+ triggers: z.array(TriggerConfigSchema).default([]),
1922
+ cooldown: CooldownConfigSchema.optional(),
1923
+ input: z.record(z.string(), InputValueSchema).optional(),
1924
+ triggerSchema: z.record(z.string(), z.unknown()).optional(),
1925
+ dir: z.string().min(1).startsWith("/").optional(),
1926
+ vcsRepo: z.string().min(1).optional(),
1927
+ createdByAgentId: z.string().optional(),
1928
+ createdAt: z.string(),
1929
+ lastUpdatedAt: z.string(),
1930
+ createdBy: z.string().optional(),
1931
+ updatedBy: z.string().optional(),
1932
+ favorite: z.boolean().optional(),
1933
+ })
1934
+ .openapi("Workflow");
1811
1935
  export type Workflow = z.infer<typeof WorkflowSchema>;
1812
1936
 
1813
1937
  // --- Workflow Version ---
1814
1938
 
1815
- export const WorkflowVersionSchema = z.object({
1816
- id: z.string().uuid(),
1817
- workflowId: z.string().uuid(),
1818
- version: z.number().int().min(1),
1819
- snapshot: WorkflowSnapshotSchema,
1820
- changedByAgentId: z.string().optional(),
1821
- createdAt: z.string(),
1822
- });
1939
+ export const WorkflowVersionSchema = z
1940
+ .object({
1941
+ id: z.string().uuid(),
1942
+ workflowId: z.string().uuid(),
1943
+ version: z.number().int().min(1),
1944
+ snapshot: WorkflowSnapshotSchema,
1945
+ changedByAgentId: z.string().optional(),
1946
+ createdAt: z.string(),
1947
+ })
1948
+ .openapi("WorkflowVersion");
1823
1949
  export type WorkflowVersion = z.infer<typeof WorkflowVersionSchema>;
1824
1950
 
1825
1951
  // ---------------------------------------------------------------------------
@@ -1839,34 +1965,38 @@ export type PageAuthMode = z.infer<typeof PageAuthModeSchema>;
1839
1965
  // page_versions.snapshot. Omits id / agentId / slug / timestamps (these are
1840
1966
  // invariant across versions for a given page id; the slug is a parent-only
1841
1967
  // identifier).
1842
- export const PageSnapshotSchema = z.object({
1843
- title: z.string(),
1844
- description: z.string().optional(),
1845
- contentType: PageContentTypeSchema,
1846
- authMode: PageAuthModeSchema,
1847
- passwordHash: z.string().optional(),
1848
- body: z.string(),
1849
- needsCredentials: z.array(z.string()).optional(),
1850
- });
1968
+ export const PageSnapshotSchema = z
1969
+ .object({
1970
+ title: z.string(),
1971
+ description: z.string().optional(),
1972
+ contentType: PageContentTypeSchema,
1973
+ authMode: PageAuthModeSchema,
1974
+ passwordHash: z.string().optional(),
1975
+ body: z.string(),
1976
+ needsCredentials: z.array(z.string()).optional(),
1977
+ })
1978
+ .openapi("PageSnapshot");
1851
1979
  export type PageSnapshot = z.infer<typeof PageSnapshotSchema>;
1852
1980
 
1853
- export const PageSchema = z.object({
1854
- id: z.string(),
1855
- key: AssetKeySchema,
1856
- agentId: z.string(),
1857
- slug: z.string(),
1858
- title: z.string(),
1859
- description: z.string().optional(),
1860
- contentType: PageContentTypeSchema,
1861
- authMode: PageAuthModeSchema,
1862
- passwordHash: z.string().optional(),
1863
- body: z.string(),
1864
- needsCredentials: z.array(z.string()).optional(),
1865
- viewCount: z.number().int().min(0).default(0),
1866
- createdAt: z.string(),
1867
- updatedAt: z.string(),
1868
- favorite: z.boolean().optional(),
1869
- });
1981
+ export const PageSchema = z
1982
+ .object({
1983
+ id: z.string(),
1984
+ key: AssetKeySchema,
1985
+ agentId: z.string(),
1986
+ slug: z.string(),
1987
+ title: z.string(),
1988
+ description: z.string().optional(),
1989
+ contentType: PageContentTypeSchema,
1990
+ authMode: PageAuthModeSchema,
1991
+ passwordHash: z.string().optional(),
1992
+ body: z.string(),
1993
+ needsCredentials: z.array(z.string()).optional(),
1994
+ viewCount: z.number().int().min(0).default(0),
1995
+ createdAt: z.string(),
1996
+ updatedAt: z.string(),
1997
+ favorite: z.boolean().optional(),
1998
+ })
1999
+ .openapi("Page");
1870
2000
  export type Page = z.infer<typeof PageSchema>;
1871
2001
 
1872
2002
  // ---------------------------------------------------------------------------
@@ -1934,14 +2064,16 @@ export type AgentTaskSummary = Pick<
1934
2064
  | "totalCostUsd"
1935
2065
  >;
1936
2066
 
1937
- export const PageVersionSchema = z.object({
1938
- id: z.string(),
1939
- pageId: z.string(),
1940
- version: z.number().int().min(1),
1941
- snapshot: PageSnapshotSchema,
1942
- changedByAgentId: z.string().optional(),
1943
- createdAt: z.string(),
1944
- });
2067
+ export const PageVersionSchema = z
2068
+ .object({
2069
+ id: z.string(),
2070
+ pageId: z.string(),
2071
+ version: z.number().int().min(1),
2072
+ snapshot: PageSnapshotSchema,
2073
+ changedByAgentId: z.string().optional(),
2074
+ createdAt: z.string(),
2075
+ })
2076
+ .openapi("PageVersion");
1945
2077
  export type PageVersion = z.infer<typeof PageVersionSchema>;
1946
2078
 
1947
2079
  // ---------------------------------------------------------------------------
@@ -1971,105 +2103,119 @@ const MetricQuerySchema = z.object({
1971
2103
  maxRows: z.number().int().min(1).max(500).optional(),
1972
2104
  });
1973
2105
 
1974
- export const MetricVariableSchema = z.object({
1975
- key: z
1976
- .string()
1977
- .min(1)
1978
- .regex(/^[a-zA-Z][a-zA-Z0-9_]*$/),
1979
- label: z.string().min(1).optional(),
1980
- type: MetricVariableTypeSchema.default("text"),
1981
- defaultValue: MetricParamSchema.optional(),
1982
- options: z
1983
- .array(
1984
- z.object({
1985
- label: z.string().min(1),
1986
- value: MetricParamSchema,
1987
- }),
1988
- )
1989
- .optional(),
1990
- optionsQuery: z
1991
- .object({
1992
- sql: z.string().min(1).max(10_000),
1993
- valueKey: z.string().min(1),
1994
- labelKey: z.string().min(1).optional(),
1995
- })
1996
- .optional(),
1997
- });
2106
+ export const MetricVariableSchema = z
2107
+ .object({
2108
+ key: z
2109
+ .string()
2110
+ .min(1)
2111
+ .regex(/^[a-zA-Z][a-zA-Z0-9_]*$/),
2112
+ label: z.string().min(1).optional(),
2113
+ type: MetricVariableTypeSchema.default("text"),
2114
+ defaultValue: MetricParamSchema.optional(),
2115
+ options: z
2116
+ .array(
2117
+ z.object({
2118
+ label: z.string().min(1),
2119
+ value: MetricParamSchema,
2120
+ }),
2121
+ )
2122
+ .optional(),
2123
+ optionsQuery: z
2124
+ .object({
2125
+ sql: z.string().min(1).max(10_000),
2126
+ valueKey: z.string().min(1),
2127
+ labelKey: z.string().min(1).optional(),
2128
+ })
2129
+ .optional(),
2130
+ })
2131
+ .openapi("MetricVariable");
1998
2132
  export type MetricVariable = z.infer<typeof MetricVariableSchema>;
1999
2133
 
2000
- export const MetricVizConfigSchema = z.object({
2001
- type: MetricVisualizationSchema,
2002
- x: z.string().optional(),
2003
- y: z.string().optional(),
2004
- series: z.array(z.string()).optional(),
2005
- label: z.string().optional(),
2006
- value: z.string().optional(),
2007
- columns: z
2008
- .array(
2009
- z.object({
2010
- key: z.string(),
2011
- label: z.string().optional(),
2012
- format: MetricFormatSchema.optional(),
2013
- }),
2014
- )
2015
- .optional(),
2016
- format: MetricFormatSchema.optional(),
2017
- });
2134
+ export const MetricVizConfigSchema = z
2135
+ .object({
2136
+ type: MetricVisualizationSchema,
2137
+ x: z.string().optional(),
2138
+ y: z.string().optional(),
2139
+ series: z.array(z.string()).optional(),
2140
+ label: z.string().optional(),
2141
+ value: z.string().optional(),
2142
+ columns: z
2143
+ .array(
2144
+ z.object({
2145
+ key: z.string(),
2146
+ label: z.string().optional(),
2147
+ format: MetricFormatSchema.optional(),
2148
+ }),
2149
+ )
2150
+ .optional(),
2151
+ format: MetricFormatSchema.optional(),
2152
+ })
2153
+ .openapi("MetricVizConfig");
2018
2154
  export type MetricVizConfig = z.infer<typeof MetricVizConfigSchema>;
2019
2155
 
2020
- export const MetricWidgetSchema = z.object({
2021
- id: z.string().min(1),
2022
- title: z.string().min(1),
2023
- description: z.string().optional(),
2024
- query: MetricQuerySchema,
2025
- viz: MetricVizConfigSchema,
2026
- colSpan: z.number().int().min(1).max(4).optional(),
2027
- rowSpan: z.number().int().min(1).max(4).optional(),
2028
- });
2156
+ export const MetricWidgetSchema = z
2157
+ .object({
2158
+ id: z.string().min(1),
2159
+ title: z.string().min(1),
2160
+ description: z.string().optional(),
2161
+ query: MetricQuerySchema,
2162
+ viz: MetricVizConfigSchema,
2163
+ colSpan: z.number().int().min(1).max(4).optional(),
2164
+ rowSpan: z.number().int().min(1).max(4).optional(),
2165
+ })
2166
+ .openapi("MetricWidget");
2029
2167
  export type MetricWidget = z.infer<typeof MetricWidgetSchema>;
2030
2168
 
2031
- export const MetricDefinitionSchema = z.object({
2032
- version: z.literal(1),
2033
- widgets: z.array(MetricWidgetSchema).min(1).max(24),
2034
- variables: z.array(MetricVariableSchema).max(12).optional(),
2035
- layout: z
2036
- .object({
2037
- columns: z.number().int().min(1).max(4).optional(),
2038
- })
2039
- .optional(),
2040
- refreshSeconds: z.number().int().min(5).max(3600).optional(),
2041
- });
2169
+ export const MetricDefinitionSchema = z
2170
+ .object({
2171
+ version: z.literal(1),
2172
+ widgets: z.array(MetricWidgetSchema).min(1).max(24),
2173
+ variables: z.array(MetricVariableSchema).max(12).optional(),
2174
+ layout: z
2175
+ .object({
2176
+ columns: z.number().int().min(1).max(4).optional(),
2177
+ })
2178
+ .optional(),
2179
+ refreshSeconds: z.number().int().min(5).max(3600).optional(),
2180
+ })
2181
+ .openapi("MetricDefinition");
2042
2182
  export type MetricDefinition = z.infer<typeof MetricDefinitionSchema>;
2043
2183
 
2044
- export const MetricSnapshotSchema = z.object({
2045
- title: z.string(),
2046
- description: z.string().optional(),
2047
- definition: MetricDefinitionSchema,
2048
- });
2184
+ export const MetricSnapshotSchema = z
2185
+ .object({
2186
+ title: z.string(),
2187
+ description: z.string().optional(),
2188
+ definition: MetricDefinitionSchema,
2189
+ })
2190
+ .openapi("MetricSnapshot");
2049
2191
  export type MetricSnapshot = z.infer<typeof MetricSnapshotSchema>;
2050
2192
 
2051
- export const MetricSchema = z.object({
2052
- id: z.string(),
2053
- agentId: z.string(),
2054
- slug: z.string(),
2055
- title: z.string(),
2056
- description: z.string().optional(),
2057
- definition: MetricDefinitionSchema,
2058
- createdAt: z.string(),
2059
- updatedAt: z.string(),
2060
- });
2193
+ export const MetricSchema = z
2194
+ .object({
2195
+ id: z.string(),
2196
+ agentId: z.string(),
2197
+ slug: z.string(),
2198
+ title: z.string(),
2199
+ description: z.string().optional(),
2200
+ definition: MetricDefinitionSchema,
2201
+ createdAt: z.string(),
2202
+ updatedAt: z.string(),
2203
+ })
2204
+ .openapi("Metric");
2061
2205
  export type Metric = z.infer<typeof MetricSchema>;
2062
2206
 
2063
2207
  export type MetricSummary = Omit<Metric, "definition">;
2064
2208
 
2065
- export const MetricVersionSchema = z.object({
2066
- id: z.string(),
2067
- metricId: z.string(),
2068
- version: z.number().int().min(1),
2069
- snapshot: MetricSnapshotSchema,
2070
- changedByAgentId: z.string().optional(),
2071
- createdAt: z.string(),
2072
- });
2209
+ export const MetricVersionSchema = z
2210
+ .object({
2211
+ id: z.string(),
2212
+ metricId: z.string(),
2213
+ version: z.number().int().min(1),
2214
+ snapshot: MetricSnapshotSchema,
2215
+ changedByAgentId: z.string().optional(),
2216
+ createdAt: z.string(),
2217
+ })
2218
+ .openapi("MetricVersion");
2073
2219
  export type MetricVersion = z.infer<typeof MetricVersionSchema>;
2074
2220
 
2075
2221
  // --- Workflow Run ---
@@ -2084,17 +2230,19 @@ export const WorkflowRunStatusSchema = z.enum([
2084
2230
  ]);
2085
2231
  export type WorkflowRunStatus = z.infer<typeof WorkflowRunStatusSchema>;
2086
2232
 
2087
- export const WorkflowRunSchema = z.object({
2088
- id: z.string().uuid(),
2089
- workflowId: z.string().uuid(),
2090
- status: WorkflowRunStatusSchema,
2091
- triggerData: z.unknown().optional(),
2092
- context: z.record(z.string(), z.unknown()).optional(),
2093
- error: z.string().optional(),
2094
- startedAt: z.string(),
2095
- lastUpdatedAt: z.string(),
2096
- finishedAt: z.string().optional(),
2097
- });
2233
+ export const WorkflowRunSchema = z
2234
+ .object({
2235
+ id: z.string().uuid(),
2236
+ workflowId: z.string().uuid(),
2237
+ status: WorkflowRunStatusSchema,
2238
+ triggerData: z.unknown().optional(),
2239
+ context: z.record(z.string(), z.unknown()).optional(),
2240
+ error: z.string().optional(),
2241
+ startedAt: z.string(),
2242
+ lastUpdatedAt: z.string(),
2243
+ finishedAt: z.string().optional(),
2244
+ })
2245
+ .openapi("WorkflowRun");
2098
2246
  export type WorkflowRun = z.infer<typeof WorkflowRunSchema>;
2099
2247
 
2100
2248
  // --- Script Workflow Runs ---
@@ -2122,23 +2270,25 @@ export type TerminalScriptRunStatus = (typeof TERMINAL_SCRIPT_RUN_STATUSES)[numb
2122
2270
  export const ScriptRunKindSchema = z.enum(["workflow", "inline"]);
2123
2271
  export type ScriptRunKind = z.infer<typeof ScriptRunKindSchema>;
2124
2272
 
2125
- export const ScriptRunSchema = z.object({
2126
- id: z.string().uuid(),
2127
- agentId: z.string(),
2128
- scriptName: z.string().optional(),
2129
- source: z.string(),
2130
- args: z.unknown(),
2131
- kind: ScriptRunKindSchema,
2132
- status: ScriptRunStatusSchema,
2133
- pid: z.number().int().optional(),
2134
- startedAt: z.string(),
2135
- finishedAt: z.string().optional(),
2136
- output: z.unknown().optional(),
2137
- error: z.string().optional(),
2138
- lastHeartbeatAt: z.string().optional(),
2139
- idempotencyKey: z.string().optional(),
2140
- requestedByUserId: z.string().optional(),
2141
- });
2273
+ export const ScriptRunSchema = z
2274
+ .object({
2275
+ id: z.string().uuid(),
2276
+ agentId: z.string(),
2277
+ scriptName: z.string().optional(),
2278
+ source: z.string(),
2279
+ args: z.unknown(),
2280
+ kind: ScriptRunKindSchema,
2281
+ status: ScriptRunStatusSchema,
2282
+ pid: z.number().int().optional(),
2283
+ startedAt: z.string(),
2284
+ finishedAt: z.string().optional(),
2285
+ output: z.unknown().optional(),
2286
+ error: z.string().optional(),
2287
+ lastHeartbeatAt: z.string().optional(),
2288
+ idempotencyKey: z.string().optional(),
2289
+ requestedByUserId: z.string().optional(),
2290
+ })
2291
+ .openapi("ScriptRun");
2142
2292
  export type ScriptRun = z.infer<typeof ScriptRunSchema>;
2143
2293
 
2144
2294
  export const ScriptRunListItemSchema = ScriptRunSchema.omit({
@@ -2148,19 +2298,21 @@ export const ScriptRunListItemSchema = ScriptRunSchema.omit({
2148
2298
  });
2149
2299
  export type ScriptRunListItem = z.infer<typeof ScriptRunListItemSchema>;
2150
2300
 
2151
- export const ScriptRunJournalEntrySchema = z.object({
2152
- id: z.string().uuid(),
2153
- runId: z.string().uuid(),
2154
- stepKey: z.string(),
2155
- stepType: z.string(),
2156
- config: z.record(z.string(), z.unknown()),
2157
- status: z.enum(["completed", "failed"]),
2158
- result: z.unknown().optional(),
2159
- error: z.string().optional(),
2160
- startedAt: z.string(),
2161
- completedAt: z.string().optional(),
2162
- durationMs: z.number().optional(),
2163
- });
2301
+ export const ScriptRunJournalEntrySchema = z
2302
+ .object({
2303
+ id: z.string().uuid(),
2304
+ runId: z.string().uuid(),
2305
+ stepKey: z.string(),
2306
+ stepType: z.string(),
2307
+ config: z.record(z.string(), z.unknown()),
2308
+ status: z.enum(["completed", "failed"]),
2309
+ result: z.unknown().optional(),
2310
+ error: z.string().optional(),
2311
+ startedAt: z.string(),
2312
+ completedAt: z.string().optional(),
2313
+ durationMs: z.number().optional(),
2314
+ })
2315
+ .openapi("ScriptRunJournalEntry");
2164
2316
  export type ScriptRunJournalEntry = z.infer<typeof ScriptRunJournalEntrySchema>;
2165
2317
 
2166
2318
  // --- Workflow Run Step ---
@@ -2176,24 +2328,26 @@ export const WorkflowRunStepStatusSchema = z.enum([
2176
2328
  ]);
2177
2329
  export type WorkflowRunStepStatus = z.infer<typeof WorkflowRunStepStatusSchema>;
2178
2330
 
2179
- export const WorkflowRunStepSchema = z.object({
2180
- id: z.string().uuid(),
2181
- runId: z.string().uuid(),
2182
- nodeId: z.string(),
2183
- nodeType: z.string(),
2184
- status: WorkflowRunStepStatusSchema,
2185
- input: z.unknown().optional(),
2186
- output: z.unknown().optional(),
2187
- error: z.string().optional(),
2188
- startedAt: z.string(),
2189
- finishedAt: z.string().optional(),
2190
- retryCount: z.number().int().min(0).default(0),
2191
- maxRetries: z.number().int().min(0).default(3),
2192
- nextRetryAt: z.string().optional(),
2193
- idempotencyKey: z.string().optional(),
2194
- diagnostics: z.string().optional(),
2195
- nextPort: z.string().optional(),
2196
- });
2331
+ export const WorkflowRunStepSchema = z
2332
+ .object({
2333
+ id: z.string().uuid(),
2334
+ runId: z.string().uuid(),
2335
+ nodeId: z.string(),
2336
+ nodeType: z.string(),
2337
+ status: WorkflowRunStepStatusSchema,
2338
+ input: z.unknown().optional(),
2339
+ output: z.unknown().optional(),
2340
+ error: z.string().optional(),
2341
+ startedAt: z.string(),
2342
+ finishedAt: z.string().optional(),
2343
+ retryCount: z.number().int().min(0).default(0),
2344
+ maxRetries: z.number().int().min(0).default(3),
2345
+ nextRetryAt: z.string().optional(),
2346
+ idempotencyKey: z.string().optional(),
2347
+ diagnostics: z.string().optional(),
2348
+ nextPort: z.string().optional(),
2349
+ })
2350
+ .openapi("WorkflowRunStep");
2197
2351
  export type WorkflowRunStep = z.infer<typeof WorkflowRunStepSchema>;
2198
2352
 
2199
2353
  // --- Wait State (workflow `wait` node side table) ---
@@ -2213,22 +2367,24 @@ export type WaitStateStatus = z.infer<typeof WaitStateStatusSchema>;
2213
2367
  * key/dot-path object OR arrow-fn body string); `expiresAt` is set when the
2214
2368
  * wait carries a timeout.
2215
2369
  */
2216
- export const WaitStateRowSchema = z.object({
2217
- id: z.string(),
2218
- workflowRunId: z.string(),
2219
- workflowRunStepId: z.string(),
2220
- mode: WaitModeSchema,
2221
- wakeUpAt: z.string().nullable(),
2222
- eventName: z.string().nullable(),
2223
- eventFilter: z.union([z.record(z.string(), z.unknown()), z.string()]).nullable(),
2224
- expiresAt: z.string().nullable(),
2225
- status: WaitStateStatusSchema,
2226
- firedPayload: z.unknown().nullable(),
2227
- resolvedAt: z.string().nullable(),
2228
- createdAt: z.string(),
2229
- updatedAt: z.string(),
2230
- eventScope: z.enum(["run", "global"]),
2231
- });
2370
+ export const WaitStateRowSchema = z
2371
+ .object({
2372
+ id: z.string(),
2373
+ workflowRunId: z.string(),
2374
+ workflowRunStepId: z.string(),
2375
+ mode: WaitModeSchema,
2376
+ wakeUpAt: z.string().nullable(),
2377
+ eventName: z.string().nullable(),
2378
+ eventFilter: z.union([z.record(z.string(), z.unknown()), z.string()]).nullable(),
2379
+ expiresAt: z.string().nullable(),
2380
+ status: WaitStateStatusSchema,
2381
+ firedPayload: z.unknown().nullable(),
2382
+ resolvedAt: z.string().nullable(),
2383
+ createdAt: z.string(),
2384
+ updatedAt: z.string(),
2385
+ eventScope: z.enum(["run", "global"]),
2386
+ })
2387
+ .openapi("WaitStateRow");
2232
2388
  export type WaitStateRow = z.infer<typeof WaitStateRowSchema>;
2233
2389
 
2234
2390
  // ============================================================================
@@ -2242,31 +2398,35 @@ export const PromptTemplateStateSchema = z.enum([
2242
2398
  "skip_event",
2243
2399
  ]);
2244
2400
 
2245
- export const PromptTemplateSchema = z.object({
2246
- id: z.string(),
2247
- eventType: z.string(),
2248
- scope: PromptTemplateScopeSchema,
2249
- scopeId: z.string().nullable(),
2250
- state: PromptTemplateStateSchema,
2251
- body: z.string(),
2252
- isDefault: z.boolean(),
2253
- version: z.number(),
2254
- createdBy: z.string().nullable(),
2255
- createdAt: z.string(),
2256
- updatedAt: z.string(),
2257
- });
2401
+ export const PromptTemplateSchema = z
2402
+ .object({
2403
+ id: z.string(),
2404
+ eventType: z.string(),
2405
+ scope: PromptTemplateScopeSchema,
2406
+ scopeId: z.string().nullable(),
2407
+ state: PromptTemplateStateSchema,
2408
+ body: z.string(),
2409
+ isDefault: z.boolean(),
2410
+ version: z.number(),
2411
+ createdBy: z.string().nullable(),
2412
+ createdAt: z.string(),
2413
+ updatedAt: z.string(),
2414
+ })
2415
+ .openapi("PromptTemplate");
2258
2416
  export type PromptTemplate = z.infer<typeof PromptTemplateSchema>;
2259
2417
 
2260
- export const PromptTemplateHistorySchema = z.object({
2261
- id: z.string(),
2262
- templateId: z.string(),
2263
- version: z.number(),
2264
- body: z.string(),
2265
- state: z.string(),
2266
- changedBy: z.string().nullable(),
2267
- changedAt: z.string(),
2268
- changeReason: z.string().nullable(),
2269
- });
2418
+ export const PromptTemplateHistorySchema = z
2419
+ .object({
2420
+ id: z.string(),
2421
+ templateId: z.string(),
2422
+ version: z.number(),
2423
+ body: z.string(),
2424
+ state: z.string(),
2425
+ changedBy: z.string().nullable(),
2426
+ changedAt: z.string(),
2427
+ changeReason: z.string().nullable(),
2428
+ })
2429
+ .openapi("PromptTemplateHistory");
2270
2430
  export type PromptTemplateHistory = z.infer<typeof PromptTemplateHistorySchema>;
2271
2431
 
2272
2432
  // ============================================================================
@@ -2279,40 +2439,44 @@ export type ScriptScope = z.infer<typeof ScriptScopeSchema>;
2279
2439
  export const ScriptFsModeSchema = z.enum(["none", "workspace-rw"]);
2280
2440
  export type ScriptFsMode = z.infer<typeof ScriptFsModeSchema>;
2281
2441
 
2282
- export const ScriptRecordSchema = z.object({
2283
- id: z.string(),
2284
- name: z.string(),
2285
- scope: ScriptScopeSchema,
2286
- scopeId: z.string().nullable(),
2287
- source: z.string(),
2288
- description: z.string(),
2289
- intent: z.string(),
2290
- signatureJson: z.string(),
2291
- argsJsonSchema: z.string().nullable(),
2292
- contentHash: z.string(),
2293
- version: z.number(),
2294
- isScratch: z.boolean(),
2295
- typeChecked: z.boolean(),
2296
- fsMode: ScriptFsModeSchema,
2297
- createdByAgentId: z.string().nullable(),
2298
- createdAt: z.string(),
2299
- updatedAt: z.string(),
2300
- });
2442
+ export const ScriptRecordSchema = z
2443
+ .object({
2444
+ id: z.string(),
2445
+ name: z.string(),
2446
+ scope: ScriptScopeSchema,
2447
+ scopeId: z.string().nullable(),
2448
+ source: z.string(),
2449
+ description: z.string(),
2450
+ intent: z.string(),
2451
+ signatureJson: z.string(),
2452
+ argsJsonSchema: z.string().nullable(),
2453
+ contentHash: z.string(),
2454
+ version: z.number(),
2455
+ isScratch: z.boolean(),
2456
+ typeChecked: z.boolean(),
2457
+ fsMode: ScriptFsModeSchema,
2458
+ createdByAgentId: z.string().nullable(),
2459
+ createdAt: z.string(),
2460
+ updatedAt: z.string(),
2461
+ })
2462
+ .openapi("ScriptRecord");
2301
2463
  export type ScriptRecord = z.infer<typeof ScriptRecordSchema>;
2302
2464
 
2303
- export const ScriptVersionRecordSchema = z.object({
2304
- id: z.string(),
2305
- scriptId: z.string(),
2306
- version: z.number(),
2307
- source: z.string(),
2308
- description: z.string(),
2309
- intent: z.string(),
2310
- signatureJson: z.string(),
2311
- contentHash: z.string(),
2312
- changedByAgentId: z.string().nullable(),
2313
- changedAt: z.string(),
2314
- changeReason: z.string().nullable(),
2315
- });
2465
+ export const ScriptVersionRecordSchema = z
2466
+ .object({
2467
+ id: z.string(),
2468
+ scriptId: z.string(),
2469
+ version: z.number(),
2470
+ source: z.string(),
2471
+ description: z.string(),
2472
+ intent: z.string(),
2473
+ signatureJson: z.string(),
2474
+ contentHash: z.string(),
2475
+ changedByAgentId: z.string().nullable(),
2476
+ changedAt: z.string(),
2477
+ changeReason: z.string().nullable(),
2478
+ })
2479
+ .openapi("ScriptVersionRecord");
2316
2480
  export type ScriptVersionRecord = z.infer<typeof ScriptVersionRecordSchema>;
2317
2481
 
2318
2482
  /** Lean projection served by `GET /api/scripts` — omits `source` (payload size) and raw JSON blobs. */
@@ -2333,17 +2497,19 @@ export const ScriptApiAuthModeSchema = z.enum(["none", "bearer"]);
2333
2497
  export type ScriptApiAuthMode = z.infer<typeof ScriptApiAuthModeSchema>;
2334
2498
 
2335
2499
  /** A script exposed as an externally-callable HTTP endpoint. Never carries the token. */
2336
- export const ScriptApiRecordSchema = z.object({
2337
- id: z.string(),
2338
- scriptId: z.string(),
2339
- agentId: z.string(),
2340
- authMode: ScriptApiAuthModeSchema,
2341
- enabled: z.boolean(),
2342
- label: z.string().nullable(),
2343
- callCount: z.number(),
2344
- lastUsedAt: z.string().nullable(),
2345
- createdAt: z.string(),
2346
- });
2500
+ export const ScriptApiRecordSchema = z
2501
+ .object({
2502
+ id: z.string(),
2503
+ scriptId: z.string(),
2504
+ agentId: z.string(),
2505
+ authMode: ScriptApiAuthModeSchema,
2506
+ enabled: z.boolean(),
2507
+ label: z.string().nullable(),
2508
+ callCount: z.number(),
2509
+ lastUsedAt: z.string().nullable(),
2510
+ createdAt: z.string(),
2511
+ })
2512
+ .openapi("ScriptApiRecord");
2347
2513
  export type ScriptApiRecord = z.infer<typeof ScriptApiRecordSchema>;
2348
2514
 
2349
2515
  /**
@@ -2363,43 +2529,47 @@ export type SkillType = z.infer<typeof SkillTypeSchema>;
2363
2529
  export const SkillScopeSchema = z.enum(["global", "swarm", "agent"]);
2364
2530
  export type SkillScope = z.infer<typeof SkillScopeSchema>;
2365
2531
 
2366
- export const SkillSchema = z.object({
2367
- id: z.string(),
2368
- name: z.string(),
2369
- description: z.string(),
2370
- content: z.string(),
2371
- type: SkillTypeSchema,
2372
- scope: SkillScopeSchema,
2373
- ownerAgentId: z.string().nullable(),
2374
- sourceUrl: z.string().nullable(),
2375
- sourceRepo: z.string().nullable(),
2376
- sourcePath: z.string().nullable(),
2377
- sourceBranch: z.string(),
2378
- sourceHash: z.string().nullable(),
2379
- isComplex: z.boolean(),
2380
- allowedTools: z.string().nullable(),
2381
- model: z.string().nullable(),
2382
- effort: z.string().nullable(),
2383
- context: z.string().nullable(),
2384
- agent: z.string().nullable(),
2385
- disableModelInvocation: z.boolean(),
2386
- userInvocable: z.boolean(),
2387
- version: z.number(),
2388
- isEnabled: z.boolean(),
2389
- systemDefault: z.boolean(),
2390
- createdAt: z.string(),
2391
- lastUpdatedAt: z.string(),
2392
- lastFetchedAt: z.string().nullable(),
2393
- });
2532
+ export const SkillSchema = z
2533
+ .object({
2534
+ id: z.string(),
2535
+ name: z.string(),
2536
+ description: z.string(),
2537
+ content: z.string(),
2538
+ type: SkillTypeSchema,
2539
+ scope: SkillScopeSchema,
2540
+ ownerAgentId: z.string().nullable(),
2541
+ sourceUrl: z.string().nullable(),
2542
+ sourceRepo: z.string().nullable(),
2543
+ sourcePath: z.string().nullable(),
2544
+ sourceBranch: z.string(),
2545
+ sourceHash: z.string().nullable(),
2546
+ isComplex: z.boolean(),
2547
+ allowedTools: z.string().nullable(),
2548
+ model: z.string().nullable(),
2549
+ effort: z.string().nullable(),
2550
+ context: z.string().nullable(),
2551
+ agent: z.string().nullable(),
2552
+ disableModelInvocation: z.boolean(),
2553
+ userInvocable: z.boolean(),
2554
+ version: z.number(),
2555
+ isEnabled: z.boolean(),
2556
+ systemDefault: z.boolean(),
2557
+ createdAt: z.string(),
2558
+ lastUpdatedAt: z.string(),
2559
+ lastFetchedAt: z.string().nullable(),
2560
+ })
2561
+ .openapi("Skill");
2394
2562
  export type Skill = z.infer<typeof SkillSchema>;
2395
2563
 
2396
- export const AgentSkillSchema = z.object({
2397
- id: z.string(),
2398
- agentId: z.string(),
2399
- skillId: z.string(),
2400
- isActive: z.boolean(),
2401
- installedAt: z.string(),
2402
- });
2564
+ export const AgentSkillSchema = z
2565
+ .object({
2566
+ id: z.string(),
2567
+ agentId: z.string(),
2568
+ skillId: z.string(),
2569
+ isActive: z.boolean(),
2570
+ installedAt: z.string(),
2571
+ })
2572
+ .openapi("AgentSkill");
2403
2573
  export type AgentSkill = z.infer<typeof AgentSkillSchema>;
2404
2574
 
2405
2575
  export const SkillWithInstallInfoSchema = SkillSchema.extend({
@@ -2408,17 +2578,19 @@ export const SkillWithInstallInfoSchema = SkillSchema.extend({
2408
2578
  });
2409
2579
  export type SkillWithInstallInfo = z.infer<typeof SkillWithInstallInfoSchema>;
2410
2580
 
2411
- export const SkillFileSchema = z.object({
2412
- id: z.string(),
2413
- skillId: z.string(),
2414
- path: z.string(),
2415
- content: z.string(),
2416
- mimeType: z.string(),
2417
- isBinary: z.boolean(),
2418
- size: z.number().nullable(),
2419
- createdAt: z.string(),
2420
- lastUpdatedAt: z.string(),
2421
- });
2581
+ export const SkillFileSchema = z
2582
+ .object({
2583
+ id: z.string(),
2584
+ skillId: z.string(),
2585
+ path: z.string(),
2586
+ content: z.string(),
2587
+ mimeType: z.string(),
2588
+ isBinary: z.boolean(),
2589
+ size: z.number().nullable(),
2590
+ createdAt: z.string(),
2591
+ lastUpdatedAt: z.string(),
2592
+ })
2593
+ .openapi("SkillFile");
2422
2594
  export type SkillFile = z.infer<typeof SkillFileSchema>;
2423
2595
 
2424
2596
  // ── MCP Servers ──────────────────────────────────────────────────────────
@@ -2432,35 +2604,39 @@ export type McpServerScope = z.infer<typeof McpServerScopeSchema>;
2432
2604
  export const McpAuthMethodSchema = z.enum(["static", "oauth", "auto"]);
2433
2605
  export type McpAuthMethod = z.infer<typeof McpAuthMethodSchema>;
2434
2606
 
2435
- export const McpServerSchema = z.object({
2436
- id: z.string(),
2437
- name: z.string(),
2438
- description: z.string().nullable(),
2439
- scope: McpServerScopeSchema,
2440
- ownerAgentId: z.string().nullable(),
2441
- transport: McpServerTransportSchema,
2442
- command: z.string().nullable(),
2443
- args: z.string().nullable(),
2444
- url: z.string().nullable(),
2445
- headers: z.string().nullable(),
2446
- envConfigKeys: z.string().nullable(),
2447
- headerConfigKeys: z.string().nullable(),
2448
- extraAuthorizeParams: z.string().nullable(),
2449
- authMethod: McpAuthMethodSchema.default("static"),
2450
- isEnabled: z.boolean(),
2451
- version: z.number(),
2452
- createdAt: z.string(),
2453
- lastUpdatedAt: z.string(),
2454
- });
2607
+ export const McpServerSchema = z
2608
+ .object({
2609
+ id: z.string(),
2610
+ name: z.string(),
2611
+ description: z.string().nullable(),
2612
+ scope: McpServerScopeSchema,
2613
+ ownerAgentId: z.string().nullable(),
2614
+ transport: McpServerTransportSchema,
2615
+ command: z.string().nullable(),
2616
+ args: z.string().nullable(),
2617
+ url: z.string().nullable(),
2618
+ headers: z.string().nullable(),
2619
+ envConfigKeys: z.string().nullable(),
2620
+ headerConfigKeys: z.string().nullable(),
2621
+ extraAuthorizeParams: z.string().nullable(),
2622
+ authMethod: McpAuthMethodSchema.default("static"),
2623
+ isEnabled: z.boolean(),
2624
+ version: z.number(),
2625
+ createdAt: z.string(),
2626
+ lastUpdatedAt: z.string(),
2627
+ })
2628
+ .openapi("McpServer");
2455
2629
  export type McpServer = z.infer<typeof McpServerSchema>;
2456
2630
 
2457
- export const AgentMcpServerSchema = z.object({
2458
- id: z.string(),
2459
- agentId: z.string(),
2460
- mcpServerId: z.string(),
2461
- isActive: z.boolean(),
2462
- installedAt: z.string(),
2463
- });
2631
+ export const AgentMcpServerSchema = z
2632
+ .object({
2633
+ id: z.string(),
2634
+ agentId: z.string(),
2635
+ mcpServerId: z.string(),
2636
+ isActive: z.boolean(),
2637
+ installedAt: z.string(),
2638
+ })
2639
+ .openapi("AgentMcpServer");
2464
2640
  export type AgentMcpServer = z.infer<typeof AgentMcpServerSchema>;
2465
2641
 
2466
2642
  export const McpServerWithInstallInfoSchema = McpServerSchema.extend({
@@ -2491,35 +2667,37 @@ export const ContextFormulaSchema = z.enum([
2491
2667
  ]);
2492
2668
  export type ContextFormula = z.infer<typeof ContextFormulaSchema>;
2493
2669
 
2494
- export const ContextSnapshotSchema = z.object({
2495
- id: z.uuid(),
2496
- taskId: z.uuid(),
2497
- agentId: z.string(),
2498
- sessionId: z.string(),
2670
+ export const ContextSnapshotSchema = z
2671
+ .object({
2672
+ id: z.uuid(),
2673
+ taskId: z.uuid(),
2674
+ agentId: z.string(),
2675
+ sessionId: z.string(),
2499
2676
 
2500
- // Context window state
2501
- contextUsedTokens: z.number().int().min(0).optional(),
2502
- contextTotalTokens: z.number().int().min(0).optional(),
2503
- contextPercent: z.number().min(0).max(100).optional(),
2677
+ // Context window state
2678
+ contextUsedTokens: z.number().int().min(0).optional(),
2679
+ contextTotalTokens: z.number().int().min(0).optional(),
2680
+ contextPercent: z.number().min(0).max(100).optional(),
2504
2681
 
2505
- // Event metadata
2506
- eventType: ContextSnapshotEventTypeSchema,
2682
+ // Event metadata
2683
+ eventType: ContextSnapshotEventTypeSchema,
2507
2684
 
2508
- // Compaction-specific (null for non-compaction)
2509
- compactTrigger: z.enum(["auto", "manual", "auto-inferred"]).optional(),
2510
- preCompactTokens: z.number().int().min(0).optional(),
2685
+ // Compaction-specific (null for non-compaction)
2686
+ compactTrigger: z.enum(["auto", "manual", "auto-inferred"]).optional(),
2687
+ preCompactTokens: z.number().int().min(0).optional(),
2511
2688
 
2512
- // Cumulative counters at this point
2513
- cumulativeInputTokens: z.number().int().min(0).default(0),
2514
- cumulativeOutputTokens: z.number().int().min(0).default(0),
2689
+ // Cumulative counters at this point
2690
+ cumulativeInputTokens: z.number().int().min(0).default(0),
2691
+ cumulativeOutputTokens: z.number().int().min(0).default(0),
2515
2692
 
2516
- // Migration 063 — adapter stamps the formula it used to compute
2517
- // contextUsedTokens. Optional so old rows / new providers without a tag
2518
- // don't break, but every adapter should populate this going forward.
2519
- contextFormula: ContextFormulaSchema.optional(),
2693
+ // Migration 063 — adapter stamps the formula it used to compute
2694
+ // contextUsedTokens. Optional so old rows / new providers without a tag
2695
+ // don't break, but every adapter should populate this going forward.
2696
+ contextFormula: ContextFormulaSchema.optional(),
2520
2697
 
2521
- createdAt: z.iso.datetime(),
2522
- });
2698
+ createdAt: z.iso.datetime(),
2699
+ })
2700
+ .openapi("ContextSnapshot");
2523
2701
 
2524
2702
  export type ContextSnapshot = z.infer<typeof ContextSnapshotSchema>;
2525
2703
 
@@ -2536,13 +2714,15 @@ export type ContextSnapshot = z.infer<typeof ContextSnapshotSchema>;
2536
2714
  export const BudgetScopeSchema = z.enum(["global", "agent", "user"]);
2537
2715
  export type BudgetScope = z.infer<typeof BudgetScopeSchema>;
2538
2716
 
2539
- export const BudgetSchema = z.object({
2540
- scope: BudgetScopeSchema,
2541
- scopeId: z.string(), // '' (empty string) for the global row
2542
- dailyBudgetUsd: z.number().nonnegative(),
2543
- createdAt: z.number(), // epoch ms
2544
- lastUpdatedAt: z.number(), // epoch ms
2545
- });
2717
+ export const BudgetSchema = z
2718
+ .object({
2719
+ scope: BudgetScopeSchema,
2720
+ scopeId: z.string(), // '' (empty string) for the global row
2721
+ dailyBudgetUsd: z.number().nonnegative(),
2722
+ createdAt: z.number(), // epoch ms
2723
+ lastUpdatedAt: z.number(), // epoch ms
2724
+ })
2725
+ .openapi("Budget");
2546
2726
  export type Budget = z.infer<typeof BudgetSchema>;
2547
2727
 
2548
2728
  // Migration 063 widened both enums and dropped the SQL CHECKs to match.
@@ -2572,34 +2752,38 @@ export const PricingTokenClassSchema = z.enum([
2572
2752
  ]);
2573
2753
  export type PricingTokenClass = z.infer<typeof PricingTokenClassSchema>;
2574
2754
 
2575
- export const PricingRowSchema = z.object({
2576
- provider: PricingProviderSchema,
2577
- model: z.string(),
2578
- tokenClass: PricingTokenClassSchema,
2579
- effectiveFrom: z.number().nonnegative(), // epoch ms; 0 = seed
2580
- pricePerMillionUsd: z.number().nonnegative(),
2581
- createdAt: z.number(), // epoch ms
2582
- lastUpdatedAt: z.number(), // epoch ms
2583
- });
2755
+ export const PricingRowSchema = z
2756
+ .object({
2757
+ provider: PricingProviderSchema,
2758
+ model: z.string(),
2759
+ tokenClass: PricingTokenClassSchema,
2760
+ effectiveFrom: z.number().nonnegative(), // epoch ms; 0 = seed
2761
+ pricePerMillionUsd: z.number().nonnegative(),
2762
+ createdAt: z.number(), // epoch ms
2763
+ lastUpdatedAt: z.number(), // epoch ms
2764
+ })
2765
+ .openapi("PricingRow");
2584
2766
  export type PricingRow = z.infer<typeof PricingRowSchema>;
2585
2767
 
2586
2768
  export const BudgetRefusalCauseSchema = z.enum(["agent", "global", "user"]);
2587
2769
  export type BudgetRefusalCause = z.infer<typeof BudgetRefusalCauseSchema>;
2588
2770
 
2589
- export const BudgetRefusalNotificationSchema = z.object({
2590
- taskId: z.string(),
2591
- date: z.string(), // 'YYYY-MM-DD' UTC
2592
- agentId: z.string(),
2593
- cause: BudgetRefusalCauseSchema,
2594
- agentSpendUsd: z.number().nullable().optional(),
2595
- agentBudgetUsd: z.number().nullable().optional(),
2596
- globalSpendUsd: z.number().nullable().optional(),
2597
- globalBudgetUsd: z.number().nullable().optional(),
2598
- userSpendUsd: z.number().nullable().optional(),
2599
- userBudgetUsd: z.number().nullable().optional(),
2600
- followUpTaskId: z.string().nullable().optional(),
2601
- createdAt: z.number(), // epoch ms
2602
- });
2771
+ export const BudgetRefusalNotificationSchema = z
2772
+ .object({
2773
+ taskId: z.string(),
2774
+ date: z.string(), // 'YYYY-MM-DD' UTC
2775
+ agentId: z.string(),
2776
+ cause: BudgetRefusalCauseSchema,
2777
+ agentSpendUsd: z.number().nullable().optional(),
2778
+ agentBudgetUsd: z.number().nullable().optional(),
2779
+ globalSpendUsd: z.number().nullable().optional(),
2780
+ globalBudgetUsd: z.number().nullable().optional(),
2781
+ userSpendUsd: z.number().nullable().optional(),
2782
+ userBudgetUsd: z.number().nullable().optional(),
2783
+ followUpTaskId: z.string().nullable().optional(),
2784
+ createdAt: z.number(), // epoch ms
2785
+ })
2786
+ .openapi("BudgetRefusalNotification");
2603
2787
  export type BudgetRefusalNotification = z.infer<typeof BudgetRefusalNotificationSchema>;
2604
2788
 
2605
2789
  /**
@@ -2609,17 +2793,19 @@ export type BudgetRefusalNotification = z.infer<typeof BudgetRefusalNotification
2609
2793
  * to default polling without back-off (degrades gracefully); Phase 4 teaches
2610
2794
  * the runner to recognize it.
2611
2795
  */
2612
- export const BudgetRefusedTriggerSchema = z.object({
2613
- type: z.literal("budget_refused"),
2614
- cause: BudgetRefusalCauseSchema,
2615
- agentSpend: z.number().optional(),
2616
- agentBudget: z.number().optional(),
2617
- globalSpend: z.number().optional(),
2618
- globalBudget: z.number().optional(),
2619
- userSpend: z.number().optional(),
2620
- userBudget: z.number().optional(),
2621
- resetAt: z.string(), // ISO 8601, next UTC midnight
2622
- });
2796
+ export const BudgetRefusedTriggerSchema = z
2797
+ .object({
2798
+ type: z.literal("budget_refused"),
2799
+ cause: BudgetRefusalCauseSchema,
2800
+ agentSpend: z.number().optional(),
2801
+ agentBudget: z.number().optional(),
2802
+ globalSpend: z.number().optional(),
2803
+ globalBudget: z.number().optional(),
2804
+ userSpend: z.number().optional(),
2805
+ userBudget: z.number().optional(),
2806
+ resetAt: z.string(), // ISO 8601, next UTC midnight
2807
+ })
2808
+ .openapi("BudgetRefusedTrigger");
2623
2809
  export type BudgetRefusedTrigger = z.infer<typeof BudgetRefusedTriggerSchema>;
2624
2810
 
2625
2811
  // ─── KV store ────────────────────────────────────────────────────────────────
@@ -2663,13 +2849,15 @@ export const KvKeySchema = z
2663
2849
  * `valueType`: `'json'` returns the parsed JS value, `'string'` returns the
2664
2850
  * raw string, `'integer'` returns a number.
2665
2851
  */
2666
- export const KvEntrySchema = z.object({
2667
- namespace: z.string(),
2668
- key: z.string(),
2669
- value: z.unknown(),
2670
- valueType: KvValueTypeSchema,
2671
- expiresAt: z.number().int().nullable(),
2672
- createdAt: z.number().int(),
2673
- updatedAt: z.number().int(),
2674
- });
2852
+ export const KvEntrySchema = z
2853
+ .object({
2854
+ namespace: z.string(),
2855
+ key: z.string(),
2856
+ value: z.unknown(),
2857
+ valueType: KvValueTypeSchema,
2858
+ expiresAt: z.number().int().nullable(),
2859
+ createdAt: z.number().int(),
2860
+ updatedAt: z.number().int(),
2861
+ })
2862
+ .openapi("KvEntry");
2675
2863
  export type KvEntry = z.infer<typeof KvEntrySchema>;