@opengeni/contracts 0.40.0 → 0.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/atlassian.d.ts +278 -0
  2. package/dist/atlassian.js +55 -0
  3. package/dist/atlassian.js.map +1 -0
  4. package/dist/chunk-52SGB2QO.js +688 -0
  5. package/dist/chunk-52SGB2QO.js.map +1 -0
  6. package/dist/{chunk-7JZMI22I.js → chunk-5UDNP7AO.js} +34 -2
  7. package/dist/chunk-5UDNP7AO.js.map +1 -0
  8. package/dist/chunk-BVGIYW7D.js +11 -0
  9. package/dist/chunk-BVGIYW7D.js.map +1 -0
  10. package/dist/chunk-CADSX6UN.js +1145 -0
  11. package/dist/chunk-CADSX6UN.js.map +1 -0
  12. package/dist/chunk-D2HKF2EF.js +1460 -0
  13. package/dist/chunk-D2HKF2EF.js.map +1 -0
  14. package/dist/chunk-FJBG5E4O.js +194 -0
  15. package/dist/chunk-FJBG5E4O.js.map +1 -0
  16. package/dist/chunk-H5BVCZKF.js +382 -0
  17. package/dist/chunk-H5BVCZKF.js.map +1 -0
  18. package/dist/chunk-LSB7GRLG.js +779 -0
  19. package/dist/chunk-LSB7GRLG.js.map +1 -0
  20. package/dist/chunk-MYBZRDTY.js +340 -0
  21. package/dist/chunk-MYBZRDTY.js.map +1 -0
  22. package/dist/chunk-RIY7GYQS.js +1204 -0
  23. package/dist/chunk-RIY7GYQS.js.map +1 -0
  24. package/dist/chunk-TZ6YEYN4.js +386 -0
  25. package/dist/chunk-TZ6YEYN4.js.map +1 -0
  26. package/dist/chunk-VA22KRHS.js +15177 -0
  27. package/dist/chunk-VA22KRHS.js.map +1 -0
  28. package/dist/chunk-Y3MLSLB4.js +392 -0
  29. package/dist/chunk-Y3MLSLB4.js.map +1 -0
  30. package/dist/chunk-YRKRZ6OF.js +134 -0
  31. package/dist/chunk-YRKRZ6OF.js.map +1 -0
  32. package/dist/company-profile.d.ts +629 -0
  33. package/dist/document-artifact-commands.d.ts +282 -0
  34. package/dist/document-artifact-commands.js +54 -0
  35. package/dist/document-artifact-commands.js.map +1 -0
  36. package/dist/document-artifact-query.d.ts +2 -0
  37. package/dist/document-artifact-query.js +54 -0
  38. package/dist/document-artifact-query.js.map +1 -0
  39. package/dist/editable-artifact-binary.d.ts +56 -0
  40. package/dist/editable-artifact-causal-frontier.d.ts +12 -0
  41. package/dist/editable-artifact-causal-frontier.js +18 -0
  42. package/dist/editable-artifact-causal-frontier.js.map +1 -0
  43. package/dist/editable-artifact-codec-registry.d.ts +48 -0
  44. package/dist/editable-artifact-codec-registry.js +20 -0
  45. package/dist/editable-artifact-codec-registry.js.map +1 -0
  46. package/dist/editable-artifact-committed-transaction.d.ts +35 -0
  47. package/dist/editable-artifact-committed-transaction.js +19 -0
  48. package/dist/editable-artifact-committed-transaction.js.map +1 -0
  49. package/dist/editable-artifact-live.d.ts +276 -0
  50. package/dist/editable-artifact-live.js +907 -0
  51. package/dist/editable-artifact-live.js.map +1 -0
  52. package/dist/editable-artifact-serialized-commit.d.ts +53 -0
  53. package/dist/editable-artifact-serialized-commit.js +26 -0
  54. package/dist/editable-artifact-serialized-commit.js.map +1 -0
  55. package/dist/editable-artifact-versions.d.ts +6 -0
  56. package/dist/editable-artifact-versions.js +11 -0
  57. package/dist/editable-artifact-versions.js.map +1 -0
  58. package/dist/editable-artifacts.d.ts +46 -0
  59. package/dist/editable-artifacts.js +236 -0
  60. package/dist/editable-artifacts.js.map +1 -0
  61. package/dist/event-preview.d.ts +1 -1
  62. package/dist/google-drive.d.ts +114 -2
  63. package/dist/google-drive.js +70 -14
  64. package/dist/google-drive.js.map +1 -1
  65. package/dist/image-generation.d.ts +70 -0
  66. package/dist/index.d.ts +4460 -155
  67. package/dist/index.js +1127 -30
  68. package/dist/interaction.d.ts +6895 -0
  69. package/dist/memory-slack-delivery.d.ts +397 -0
  70. package/dist/presentation-artifact-commands.d.ts +349 -0
  71. package/dist/presentation-artifact-commands.js +66 -0
  72. package/dist/presentation-artifact-commands.js.map +1 -0
  73. package/dist/presentation-artifact-query.d.ts +2 -0
  74. package/dist/presentation-artifact-query.js +66 -0
  75. package/dist/presentation-artifact-query.js.map +1 -0
  76. package/dist/retained-output.d.ts +24 -0
  77. package/dist/sandbox-snapshots.d.ts +9 -0
  78. package/dist/scoped-knowledge.d.ts +14 -13
  79. package/dist/slack-bot-scopes.d.ts +4 -0
  80. package/dist/slack-bot-scopes.js +3 -1
  81. package/dist/spreadsheet-artifact-commands.d.ts +101 -0
  82. package/dist/spreadsheet-artifact-commands.js +27 -0
  83. package/dist/spreadsheet-artifact-commands.js.map +1 -0
  84. package/dist/spreadsheet-artifact-date.d.ts +4 -0
  85. package/dist/spreadsheet-artifact-query.d.ts +120 -0
  86. package/dist/spreadsheet-artifact-query.js +48 -0
  87. package/dist/spreadsheet-artifact-query.js.map +1 -0
  88. package/dist/tool-catalog.d.ts +576 -0
  89. package/dist/video-generation.d.ts +532 -0
  90. package/dist/video-generation.js +51 -0
  91. package/dist/video-generation.js.map +1 -0
  92. package/dist/workspace-learning-policy.d.ts +208 -0
  93. package/package.json +61 -1
  94. package/src/atlassian.ts +160 -0
  95. package/src/company-profile.ts +306 -0
  96. package/src/document-artifact-commands.ts +1709 -0
  97. package/src/document-artifact-query.ts +2 -0
  98. package/src/editable-artifact-binary.ts +396 -0
  99. package/src/editable-artifact-causal-frontier.ts +154 -0
  100. package/src/editable-artifact-codec-registry.ts +261 -0
  101. package/src/editable-artifact-committed-transaction.ts +478 -0
  102. package/src/editable-artifact-live.ts +1379 -0
  103. package/src/editable-artifact-serialized-commit.ts +494 -0
  104. package/src/editable-artifact-versions.ts +8 -0
  105. package/src/editable-artifacts.ts +473 -0
  106. package/src/google-drive.ts +68 -15
  107. package/src/image-generation.ts +106 -0
  108. package/src/index.ts +2326 -325
  109. package/src/interaction.ts +2292 -0
  110. package/src/memory-slack-delivery.ts +183 -0
  111. package/src/presentation-artifact-commands.ts +2035 -0
  112. package/src/presentation-artifact-query.ts +2 -0
  113. package/src/retained-output.ts +149 -2
  114. package/src/sandbox-snapshots.ts +28 -1
  115. package/src/scoped-knowledge.ts +18 -4
  116. package/src/slack-bot-scopes.ts +34 -1
  117. package/src/spreadsheet-artifact-commands.ts +999 -0
  118. package/src/spreadsheet-artifact-date.ts +21 -0
  119. package/src/spreadsheet-artifact-query.ts +1411 -0
  120. package/src/tool-catalog.ts +334 -0
  121. package/src/video-generation.ts +394 -0
  122. package/src/workspace-learning-policy.ts +233 -0
  123. package/dist/chunk-5HR2GPSC.js +0 -11031
  124. package/dist/chunk-5HR2GPSC.js.map +0 -1
  125. package/dist/chunk-7JZMI22I.js.map +0 -1
@@ -0,0 +1,394 @@
1
+ import { z } from "zod";
2
+ import {
3
+ GENERATED_VIDEO_MAX_BYTES,
4
+ RETAINED_OUTPUT_MAX_PAGE_BYTES,
5
+ RetainedArtifactReferenceSchema,
6
+ } from "./retained-output";
7
+
8
+ export const VIDEO_GENERATION_SCHEMA_VERSION = 1 as const;
9
+ export const SEEDANCE_2_5_MODEL_ID = "bytedance/seedance-2.5" as const;
10
+
11
+ export const VideoGenerationSourceMode = z.enum([
12
+ "text",
13
+ "first_frame",
14
+ "first_and_last_frames",
15
+ "image_reference",
16
+ "video_reference",
17
+ ]);
18
+ export type VideoGenerationSourceMode = z.infer<typeof VideoGenerationSourceMode>;
19
+
20
+ export const VideoGenerationResolution = z.enum(["480p", "720p"]);
21
+ export type VideoGenerationResolution = z.infer<typeof VideoGenerationResolution>;
22
+
23
+ export const VideoGenerationFundingSource = z.enum(["opengeni_credits", "workspace_gateway"]);
24
+ export type VideoGenerationFundingSource = z.infer<typeof VideoGenerationFundingSource>;
25
+
26
+ export const VideoGenerationAspectRatio = z.enum([
27
+ "16:9",
28
+ "4:3",
29
+ "1:1",
30
+ "3:4",
31
+ "9:16",
32
+ "21:9",
33
+ "adaptive",
34
+ ]);
35
+ export type VideoGenerationAspectRatio = z.infer<typeof VideoGenerationAspectRatio>;
36
+
37
+ const SandboxVideoReferencePath = z
38
+ .string()
39
+ .min(1)
40
+ .max(1_024)
41
+ .refine((value) => value.startsWith("/workspace/"), {
42
+ message: "video references must use an absolute /workspace path",
43
+ });
44
+
45
+ export const VideoGenerationSource = z.discriminatedUnion("mode", [
46
+ z.object({ mode: z.literal("text") }).strict(),
47
+ z
48
+ .object({
49
+ mode: z.literal("first_frame"),
50
+ imagePath: SandboxVideoReferencePath,
51
+ })
52
+ .strict(),
53
+ z
54
+ .object({
55
+ mode: z.literal("first_and_last_frames"),
56
+ firstFramePath: SandboxVideoReferencePath,
57
+ lastFramePath: SandboxVideoReferencePath,
58
+ })
59
+ .strict()
60
+ .refine((value) => value.firstFramePath !== value.lastFramePath, {
61
+ path: ["lastFramePath"],
62
+ message: "first and last frame paths must differ",
63
+ }),
64
+ z
65
+ .object({
66
+ mode: z.literal("image_reference"),
67
+ imagePath: SandboxVideoReferencePath,
68
+ })
69
+ .strict(),
70
+ z
71
+ .object({
72
+ mode: z.literal("video_reference"),
73
+ videoPath: SandboxVideoReferencePath,
74
+ })
75
+ .strict(),
76
+ ]);
77
+ export type VideoGenerationSource = z.infer<typeof VideoGenerationSource>;
78
+
79
+ /** Stable provider-neutral function-tool input. Dynamic capability facts never enter this schema. */
80
+ export const GenerateVideoToolInput = z
81
+ .object({
82
+ prompt: z
83
+ .string()
84
+ .min(1)
85
+ .max(32_000)
86
+ .refine((value) => value.trim().length > 0),
87
+ modelId: z.string().min(1).max(256).optional(),
88
+ source: VideoGenerationSource.optional(),
89
+ durationSeconds: z.number().int().min(4).max(30).optional(),
90
+ aspectRatio: VideoGenerationAspectRatio.optional(),
91
+ resolution: VideoGenerationResolution.optional(),
92
+ generateAudio: z.boolean().optional(),
93
+ })
94
+ .strict();
95
+ export type GenerateVideoToolInput = z.infer<typeof GenerateVideoToolInput>;
96
+
97
+ export const GetVideoGenerationCapabilitiesToolInput = z.object({}).strict();
98
+ export type GetVideoGenerationCapabilitiesToolInput = z.infer<
99
+ typeof GetVideoGenerationCapabilitiesToolInput
100
+ >;
101
+
102
+ export const VideoGenerationModelCapability = z
103
+ .object({
104
+ modelId: z.string().min(1).max(256),
105
+ label: z.string().min(1).max(128),
106
+ providerLabel: z.string().min(1).max(128),
107
+ sourceModes: z.array(VideoGenerationSourceMode).min(1).max(5),
108
+ resolutions: z.array(VideoGenerationResolution).min(1).max(2),
109
+ aspectRatios: z.array(VideoGenerationAspectRatio).min(1).max(7),
110
+ duration: z
111
+ .object({
112
+ minSeconds: z.number().int().positive(),
113
+ maxSeconds: z.number().int().positive(),
114
+ stepSeconds: z.number().int().positive(),
115
+ })
116
+ .strict()
117
+ .refine((value) => value.maxSeconds >= value.minSeconds),
118
+ supportsAudio: z.boolean(),
119
+ })
120
+ .strict();
121
+ export type VideoGenerationModelCapability = z.infer<typeof VideoGenerationModelCapability>;
122
+
123
+ export const VideoGenerationCapabilities = z
124
+ .object({
125
+ schemaVersion: z.literal(VIDEO_GENERATION_SCHEMA_VERSION),
126
+ capabilityRevision: z.string().min(1).max(128),
127
+ defaultModelId: z.string().min(1).max(256),
128
+ models: z.array(VideoGenerationModelCapability).min(1).max(16),
129
+ })
130
+ .strict()
131
+ .superRefine((value, ctx) => {
132
+ const ids = new Set(value.models.map((model) => model.modelId));
133
+ if (ids.size !== value.models.length) {
134
+ ctx.addIssue({ code: "custom", path: ["models"], message: "model ids must be unique" });
135
+ }
136
+ if (!ids.has(value.defaultModelId)) {
137
+ ctx.addIssue({
138
+ code: "custom",
139
+ path: ["defaultModelId"],
140
+ message: "default model must be present in the enabled model list",
141
+ });
142
+ }
143
+ });
144
+ export type VideoGenerationCapabilities = z.infer<typeof VideoGenerationCapabilities>;
145
+
146
+ export const VideoGenerationPolicy = z
147
+ .object({
148
+ schemaVersion: z.literal(VIDEO_GENERATION_SCHEMA_VERSION),
149
+ revision: z.number().int().nonnegative().safe(),
150
+ fundingSource: VideoGenerationFundingSource,
151
+ enabledModelIds: z.array(z.string().min(1).max(256)).max(16),
152
+ defaultModelId: z.string().min(1).max(256).nullable(),
153
+ })
154
+ .strict()
155
+ .superRefine((value, ctx) => {
156
+ const ids = new Set(value.enabledModelIds);
157
+ if (ids.size !== value.enabledModelIds.length) {
158
+ ctx.addIssue({
159
+ code: "custom",
160
+ path: ["enabledModelIds"],
161
+ message: "enabled model ids must be unique",
162
+ });
163
+ }
164
+ if (value.defaultModelId !== null && !ids.has(value.defaultModelId)) {
165
+ ctx.addIssue({
166
+ code: "custom",
167
+ path: ["defaultModelId"],
168
+ message: "default model must be enabled",
169
+ });
170
+ }
171
+ });
172
+ export type VideoGenerationPolicy = z.infer<typeof VideoGenerationPolicy>;
173
+
174
+ export const UpdateVideoGenerationPolicyRequest = z
175
+ .object({
176
+ expectedRevision: z.number().int().nonnegative().safe(),
177
+ fundingSource: VideoGenerationFundingSource,
178
+ enabledModelIds: z.array(z.string().min(1).max(256)).max(16),
179
+ defaultModelId: z.string().min(1).max(256).nullable(),
180
+ })
181
+ .strict();
182
+ export type UpdateVideoGenerationPolicyRequest = z.infer<typeof UpdateVideoGenerationPolicyRequest>;
183
+
184
+ export const VideoGenerationFundingOption = z
185
+ .object({
186
+ source: VideoGenerationFundingSource,
187
+ label: z.string().min(1).max(128),
188
+ description: z.string().min(1).max(256),
189
+ available: z.boolean(),
190
+ unavailableReason: z.string().min(1).max(256).nullable(),
191
+ })
192
+ .strict()
193
+ .superRefine((value, ctx) => {
194
+ if (value.available !== (value.unavailableReason === null)) {
195
+ ctx.addIssue({
196
+ code: "custom",
197
+ path: ["unavailableReason"],
198
+ message: "available funding options cannot have an unavailable reason",
199
+ });
200
+ }
201
+ });
202
+ export type VideoGenerationFundingOption = z.infer<typeof VideoGenerationFundingOption>;
203
+
204
+ export const WorkspaceVideoGenerationSettings = z
205
+ .object({
206
+ schemaVersion: z.literal(VIDEO_GENERATION_SCHEMA_VERSION),
207
+ policy: VideoGenerationPolicy,
208
+ fundingOptions: z.array(VideoGenerationFundingOption).length(2),
209
+ availableModels: z.array(VideoGenerationModelCapability).max(16),
210
+ capabilities: VideoGenerationCapabilities.nullable(),
211
+ })
212
+ .strict()
213
+ .superRefine((value, ctx) => {
214
+ if (
215
+ new Set(value.fundingOptions.map((option) => option.source)).size !== 2 ||
216
+ !value.fundingOptions.some((option) => option.source === "opengeni_credits") ||
217
+ !value.fundingOptions.some((option) => option.source === "workspace_gateway")
218
+ ) {
219
+ ctx.addIssue({
220
+ code: "custom",
221
+ path: ["fundingOptions"],
222
+ message: "both funding sources must be described exactly once",
223
+ });
224
+ }
225
+ const selected = value.fundingOptions.find(
226
+ (option) => option.source === value.policy.fundingSource,
227
+ );
228
+ if (!selected) {
229
+ ctx.addIssue({
230
+ code: "custom",
231
+ path: ["fundingOptions"],
232
+ message: "the selected funding source must be described",
233
+ });
234
+ } else if (!selected.available && value.capabilities !== null) {
235
+ ctx.addIssue({
236
+ code: "custom",
237
+ path: ["capabilities"],
238
+ message: "unavailable funding cannot expose executable capabilities",
239
+ });
240
+ }
241
+ });
242
+ export type WorkspaceVideoGenerationSettings = z.infer<typeof WorkspaceVideoGenerationSettings>;
243
+
244
+ export const VideoGenerationAcceptedReceipt = z
245
+ .object({
246
+ schemaVersion: z.literal(VIDEO_GENERATION_SCHEMA_VERSION),
247
+ status: z.literal("accepted"),
248
+ operationId: z.string().uuid(),
249
+ })
250
+ .strict();
251
+ export type VideoGenerationAcceptedReceipt = z.infer<typeof VideoGenerationAcceptedReceipt>;
252
+
253
+ export const GeneratedVideoFacts = z
254
+ .object({
255
+ durationSeconds: z.number().positive().max(120),
256
+ width: z.number().int().positive().max(8_192),
257
+ height: z.number().int().positive().max(8_192),
258
+ fps: z.number().positive().max(120),
259
+ hasAudio: z.boolean(),
260
+ videoCodec: z.literal("h264"),
261
+ audioCodec: z.literal("aac").nullable(),
262
+ })
263
+ .strict();
264
+ export type GeneratedVideoFacts = z.infer<typeof GeneratedVideoFacts>;
265
+
266
+ export const GeneratedVideoReceipt = z
267
+ .object({
268
+ type: z.literal("generated_video"),
269
+ schemaVersion: z.literal(VIDEO_GENERATION_SCHEMA_VERSION),
270
+ operationId: z.string().uuid(),
271
+ artifact: RetainedArtifactReferenceSchema,
272
+ video: GeneratedVideoFacts,
273
+ sandboxPath: z
274
+ .string()
275
+ .max(256)
276
+ .regex(
277
+ /^\/workspace\/generated-videos\/generated-video-[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\.mp4$/,
278
+ ),
279
+ })
280
+ .strict()
281
+ .superRefine((value, ctx) => {
282
+ if (
283
+ value.artifact.kind !== "generated_video" ||
284
+ value.artifact.contentType !== "video/mp4" ||
285
+ value.artifact.originalBytes <= 0 ||
286
+ value.artifact.originalBytes > GENERATED_VIDEO_MAX_BYTES ||
287
+ value.artifact.retention.policy !== "workspace_file" ||
288
+ value.artifact.retrieval.maxRangeBytes !== RETAINED_OUTPUT_MAX_PAGE_BYTES
289
+ ) {
290
+ ctx.addIssue({
291
+ code: "custom",
292
+ path: ["artifact"],
293
+ message: "generated-video artifact metadata is invalid",
294
+ });
295
+ }
296
+ if (
297
+ value.artifact.dimensions?.width !== value.video.width ||
298
+ value.artifact.dimensions?.height !== value.video.height
299
+ ) {
300
+ ctx.addIssue({
301
+ code: "custom",
302
+ path: ["video"],
303
+ message: "video dimensions must match the retained artifact",
304
+ });
305
+ }
306
+ if (
307
+ value.sandboxPath !==
308
+ `/workspace/generated-videos/generated-video-${value.artifact.artifactId}.mp4`
309
+ ) {
310
+ ctx.addIssue({
311
+ code: "custom",
312
+ path: ["sandboxPath"],
313
+ message: "generated-video sandbox path does not match its artifact",
314
+ });
315
+ }
316
+ });
317
+ export type GeneratedVideoReceipt = z.infer<typeof GeneratedVideoReceipt>;
318
+
319
+ export const VideoGenerationTerminalFailureStatus = z.enum([
320
+ "provider_failed",
321
+ "retention_failed",
322
+ "cancelled_before_submit",
323
+ "outcome_unknown",
324
+ ]);
325
+ export type VideoGenerationTerminalFailureStatus = z.infer<
326
+ typeof VideoGenerationTerminalFailureStatus
327
+ >;
328
+
329
+ export const MediaGenerationResult = z.discriminatedUnion("status", [
330
+ z
331
+ .object({
332
+ type: z.literal("media_generation_result"),
333
+ schemaVersion: z.literal(VIDEO_GENERATION_SCHEMA_VERSION),
334
+ status: z.literal("ready"),
335
+ operationId: z.string().uuid(),
336
+ receipt: GeneratedVideoReceipt,
337
+ })
338
+ .strict()
339
+ .refine((value) => value.receipt.operationId === value.operationId, {
340
+ path: ["receipt", "operationId"],
341
+ message: "terminal receipt must match its operation",
342
+ }),
343
+ z
344
+ .object({
345
+ type: z.literal("media_generation_result"),
346
+ schemaVersion: z.literal(VIDEO_GENERATION_SCHEMA_VERSION),
347
+ status: VideoGenerationTerminalFailureStatus,
348
+ operationId: z.string().uuid(),
349
+ boundedPublicReason: z.string().min(1).max(1_000),
350
+ })
351
+ .strict(),
352
+ ]);
353
+ export type MediaGenerationResult = z.infer<typeof MediaGenerationResult>;
354
+
355
+ export const VideoGenerationPublicStatus = z.enum([
356
+ "preparing",
357
+ "prepared",
358
+ "accepted",
359
+ "provider_started",
360
+ "retaining",
361
+ "completed",
362
+ "provider_failed",
363
+ "cancelled_before_submit",
364
+ "outcome_unknown",
365
+ "retention_failed",
366
+ ]);
367
+ export type VideoGenerationPublicStatus = z.infer<typeof VideoGenerationPublicStatus>;
368
+
369
+ export const VideoGenerationOperationSummary = z
370
+ .object({
371
+ schemaVersion: z.literal(VIDEO_GENERATION_SCHEMA_VERSION),
372
+ operationId: z.string().uuid(),
373
+ modelId: z.string().min(1).max(256),
374
+ status: VideoGenerationPublicStatus,
375
+ createdAt: z.string().datetime({ offset: true }),
376
+ updatedAt: z.string().datetime({ offset: true }),
377
+ terminal: MediaGenerationResult.nullable(),
378
+ })
379
+ .strict();
380
+ export type VideoGenerationOperationSummary = z.infer<typeof VideoGenerationOperationSummary>;
381
+
382
+ export const VideoArtifactPlaybackSource = z
383
+ .object({
384
+ schemaVersion: z.literal(VIDEO_GENERATION_SCHEMA_VERSION),
385
+ artifactId: z.string().uuid(),
386
+ url: z.string().url().max(8_192),
387
+ expiresAt: z.string().datetime({ offset: true }),
388
+ contentType: z.literal("video/mp4"),
389
+ sizeBytes: z.number().int().positive().max(GENERATED_VIDEO_MAX_BYTES),
390
+ sha256: z.string().regex(/^[0-9a-f]{64}$/),
391
+ acceptRanges: z.literal("bytes"),
392
+ })
393
+ .strict();
394
+ export type VideoArtifactPlaybackSource = z.infer<typeof VideoArtifactPlaybackSource>;
@@ -0,0 +1,233 @@
1
+ import { z } from "zod";
2
+
3
+ export const WORKSPACE_LEARNING_POLICY_MAX_SOURCE_OVERRIDES = 256;
4
+ export const WORKSPACE_LEARNING_POLICY_SOURCE_KIND_MAX_CHARS = 96;
5
+ export const WORKSPACE_LEARNING_POLICY_SOURCE_ID_MAX_CHARS = 1_024;
6
+ export const WORKSPACE_LEARNING_POLICY_REASON_MAX_CHARS = 4_096;
7
+ export const WORKSPACE_LEARNING_POLICY_DEFAULT_OFF_REVISION_ID =
8
+ "workspace-learning-policy:default-off:v1";
9
+
10
+ export const WorkspaceLearningMode = z.enum(["off", "suggest", "automatic"]);
11
+ export type WorkspaceLearningMode = z.infer<typeof WorkspaceLearningMode>;
12
+
13
+ export const WorkspaceLearningOverrideMode = z.enum(["inherit", "off", "suggest", "automatic"]);
14
+ export type WorkspaceLearningOverrideMode = z.infer<typeof WorkspaceLearningOverrideMode>;
15
+
16
+ export function normalizeWorkspaceLearningSourceKind(value: string): string {
17
+ return value.normalize("NFKC").trim().toLowerCase().replace(/\s+/gu, "-").replace(/-+/g, "-");
18
+ }
19
+
20
+ export const WorkspaceLearningSourceKind = z
21
+ .string()
22
+ .transform(normalizeWorkspaceLearningSourceKind)
23
+ .pipe(
24
+ z
25
+ .string()
26
+ .min(1)
27
+ .max(WORKSPACE_LEARNING_POLICY_SOURCE_KIND_MAX_CHARS)
28
+ .regex(/^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/),
29
+ );
30
+ export type WorkspaceLearningSourceKind = z.infer<typeof WorkspaceLearningSourceKind>;
31
+
32
+ export const WorkspaceLearningSourceId = z
33
+ .string()
34
+ .min(1)
35
+ .max(WORKSPACE_LEARNING_POLICY_SOURCE_ID_MAX_CHARS)
36
+ .refine(
37
+ (value) => value.trim() === value,
38
+ "learning source ids must not contain edge whitespace",
39
+ );
40
+ export type WorkspaceLearningSourceId = z.infer<typeof WorkspaceLearningSourceId>;
41
+
42
+ export const WorkspaceLearningSourceRef = z.object({
43
+ kind: WorkspaceLearningSourceKind,
44
+ id: WorkspaceLearningSourceId,
45
+ });
46
+ export type WorkspaceLearningSourceRef = z.infer<typeof WorkspaceLearningSourceRef>;
47
+
48
+ export const WorkspaceLearningSourceOverrideInput = WorkspaceLearningSourceRef.extend({
49
+ mode: WorkspaceLearningOverrideMode,
50
+ });
51
+ export type WorkspaceLearningSourceOverrideInput = z.infer<
52
+ typeof WorkspaceLearningSourceOverrideInput
53
+ >;
54
+
55
+ export const WorkspaceLearningSourceOverride = WorkspaceLearningSourceRef.extend({
56
+ mode: WorkspaceLearningMode,
57
+ });
58
+ export type WorkspaceLearningSourceOverride = z.infer<typeof WorkspaceLearningSourceOverride>;
59
+
60
+ export const WorkspaceLearningSourceOverrides = z
61
+ .array(WorkspaceLearningSourceOverride)
62
+ .max(WORKSPACE_LEARNING_POLICY_MAX_SOURCE_OVERRIDES);
63
+ export type WorkspaceLearningSourceOverrides = z.infer<typeof WorkspaceLearningSourceOverrides>;
64
+
65
+ export function workspaceLearningSourceKey(source: WorkspaceLearningSourceRef): string {
66
+ return `${source.kind}\u0000${source.id}`;
67
+ }
68
+
69
+ function compareUtf8(left: string, right: string): number {
70
+ const encoder = new TextEncoder();
71
+ const leftBytes = encoder.encode(left);
72
+ const rightBytes = encoder.encode(right);
73
+ const length = Math.min(leftBytes.length, rightBytes.length);
74
+ for (let index = 0; index < length; index += 1) {
75
+ if (leftBytes[index] !== rightBytes[index]) return leftBytes[index]! - rightBytes[index]!;
76
+ }
77
+ return leftBytes.length - rightBytes.length;
78
+ }
79
+
80
+ /**
81
+ * Canonicalize caller input before hashing or persistence. `inherit` is a
82
+ * request-only reset operation: inherited entries are deliberately absent from
83
+ * immutable revisions so the persisted policy stays sparse and transparent.
84
+ */
85
+ export function canonicalizeWorkspaceLearningSourceOverrides(
86
+ input: readonly WorkspaceLearningSourceOverrideInput[],
87
+ ): WorkspaceLearningSourceOverride[] {
88
+ if (input.length > WORKSPACE_LEARNING_POLICY_MAX_SOURCE_OVERRIDES) {
89
+ throw new Error(
90
+ `workspace learning policy supports at most ${WORKSPACE_LEARNING_POLICY_MAX_SOURCE_OVERRIDES} source overrides`,
91
+ );
92
+ }
93
+ const seen = new Set<string>();
94
+ const canonical: WorkspaceLearningSourceOverride[] = [];
95
+ for (const candidate of input) {
96
+ const parsed = WorkspaceLearningSourceOverrideInput.parse(candidate);
97
+ const key = workspaceLearningSourceKey(parsed);
98
+ if (seen.has(key)) {
99
+ throw new Error(`duplicate workspace learning source override: ${parsed.kind}/${parsed.id}`);
100
+ }
101
+ seen.add(key);
102
+ if (parsed.mode !== "inherit") canonical.push(parsed as WorkspaceLearningSourceOverride);
103
+ }
104
+ canonical.sort((left, right) => {
105
+ const kindOrder = compareUtf8(left.kind, right.kind);
106
+ return kindOrder === 0 ? compareUtf8(left.id, right.id) : kindOrder;
107
+ });
108
+ return WorkspaceLearningSourceOverrides.parse(canonical);
109
+ }
110
+
111
+ const revisionIdentityShape = {
112
+ id: z.string().uuid(),
113
+ revision: z.number().int().positive(),
114
+ policyHash: z.string().regex(/^[0-9a-f]{64}$/),
115
+ };
116
+
117
+ export const WorkspaceLearningPolicyRevisionIdentity = z.object(revisionIdentityShape);
118
+ export type WorkspaceLearningPolicyRevisionIdentity = z.infer<
119
+ typeof WorkspaceLearningPolicyRevisionIdentity
120
+ >;
121
+
122
+ export const WorkspaceLearningPolicyRevision = z.object({
123
+ ...revisionIdentityShape,
124
+ operationId: z.string().uuid(),
125
+ accountId: z.string().uuid(),
126
+ workspaceId: z.string().uuid(),
127
+ workspaceMode: WorkspaceLearningMode,
128
+ sourceOverrides: WorkspaceLearningSourceOverrides,
129
+ supersedesRevisionId: z.string().uuid().nullable(),
130
+ createdBySubjectId: z.string().min(1),
131
+ createdAt: z.string().datetime(),
132
+ });
133
+ export type WorkspaceLearningPolicyRevision = z.infer<typeof WorkspaceLearningPolicyRevision>;
134
+
135
+ export const WorkspaceLearningPolicyHead = z.object({
136
+ accountId: z.string().uuid(),
137
+ workspaceId: z.string().uuid(),
138
+ revisionId: z.string().uuid(),
139
+ revision: z.number().int().positive(),
140
+ policyHash: z.string().regex(/^[0-9a-f]{64}$/),
141
+ activationVersion: z.number().int().positive(),
142
+ activatedAt: z.string().datetime(),
143
+ });
144
+ export type WorkspaceLearningPolicyHead = z.infer<typeof WorkspaceLearningPolicyHead>;
145
+
146
+ export const WorkspaceLearningPolicyActivationType = z.enum(["activate", "rollback"]);
147
+ export type WorkspaceLearningPolicyActivationType = z.infer<
148
+ typeof WorkspaceLearningPolicyActivationType
149
+ >;
150
+
151
+ export const WorkspaceLearningPolicyActivationEvent = z.object({
152
+ id: z.string().uuid(),
153
+ operationId: z.string().uuid(),
154
+ accountId: z.string().uuid(),
155
+ workspaceId: z.string().uuid(),
156
+ type: WorkspaceLearningPolicyActivationType,
157
+ activationVersion: z.number().int().positive(),
158
+ oldRevision: WorkspaceLearningPolicyRevisionIdentity.nullable(),
159
+ newRevision: WorkspaceLearningPolicyRevisionIdentity,
160
+ actorSubjectId: z.string().min(1),
161
+ reason: z.string().min(1).max(WORKSPACE_LEARNING_POLICY_REASON_MAX_CHARS),
162
+ createdAt: z.string().datetime(),
163
+ });
164
+ export type WorkspaceLearningPolicyActivationEvent = z.infer<
165
+ typeof WorkspaceLearningPolicyActivationEvent
166
+ >;
167
+
168
+ export const WorkspaceLearningPolicySnapshot = z.object({
169
+ id: z.string().uuid(),
170
+ accountId: z.string().uuid(),
171
+ workspaceId: z.string().uuid(),
172
+ sessionId: z.string().uuid(),
173
+ turnId: z.string().uuid(),
174
+ attemptId: z.string().uuid(),
175
+ executionGeneration: z.number().int().positive(),
176
+ revision: WorkspaceLearningPolicyRevisionIdentity.nullable(),
177
+ activationVersion: z.number().int().nonnegative(),
178
+ activatedAt: z.string().datetime().nullable(),
179
+ workspaceMode: WorkspaceLearningMode,
180
+ sourceOverrides: WorkspaceLearningSourceOverrides,
181
+ snapshotHash: z.string().regex(/^[0-9a-f]{64}$/),
182
+ createdAt: z.string().datetime(),
183
+ });
184
+ export type WorkspaceLearningPolicySnapshot = z.infer<typeof WorkspaceLearningPolicySnapshot>;
185
+
186
+ export const WorkspaceLearningPolicyRouterContext = z.object({
187
+ mode: WorkspaceLearningMode,
188
+ snapshotId: z.string().uuid(),
189
+ revisionId: z.string().min(1).max(512),
190
+ });
191
+ export type WorkspaceLearningPolicyRouterContext = z.infer<
192
+ typeof WorkspaceLearningPolicyRouterContext
193
+ >;
194
+
195
+ export const WorkspaceLearningPolicyEffectiveMode = WorkspaceLearningPolicyRouterContext.extend({
196
+ inherited: z.boolean(),
197
+ source: WorkspaceLearningSourceRef,
198
+ policyRevision: WorkspaceLearningPolicyRevisionIdentity.nullable(),
199
+ activationVersion: z.number().int().nonnegative(),
200
+ snapshotHash: z.string().regex(/^[0-9a-f]{64}$/),
201
+ });
202
+ export type WorkspaceLearningPolicyEffectiveMode = z.infer<
203
+ typeof WorkspaceLearningPolicyEffectiveMode
204
+ >;
205
+
206
+ /** Stable router seam: resolve only from an immutable accepted-attempt snapshot. */
207
+ export function resolveWorkspaceLearningPolicyEffectiveMode(
208
+ snapshot: WorkspaceLearningPolicySnapshot,
209
+ source: WorkspaceLearningSourceRef,
210
+ ): WorkspaceLearningPolicyEffectiveMode {
211
+ const parsedSnapshot = WorkspaceLearningPolicySnapshot.parse(snapshot);
212
+ const parsedSource = WorkspaceLearningSourceRef.parse(source);
213
+ const override = parsedSnapshot.sourceOverrides.find(
214
+ (candidate) => candidate.kind === parsedSource.kind && candidate.id === parsedSource.id,
215
+ );
216
+ return WorkspaceLearningPolicyEffectiveMode.parse({
217
+ mode: override?.mode ?? parsedSnapshot.workspaceMode,
218
+ inherited: override === undefined,
219
+ source: parsedSource,
220
+ policyRevision: parsedSnapshot.revision,
221
+ activationVersion: parsedSnapshot.activationVersion,
222
+ snapshotId: parsedSnapshot.id,
223
+ revisionId: parsedSnapshot.revision?.id ?? WORKSPACE_LEARNING_POLICY_DEFAULT_OFF_REVISION_ID,
224
+ snapshotHash: parsedSnapshot.snapshotHash,
225
+ });
226
+ }
227
+
228
+ /** Exact provider-neutral context consumed by the canonical durable-learning router. */
229
+ export function workspaceLearningPolicyRouterContext(
230
+ effectiveMode: WorkspaceLearningPolicyEffectiveMode,
231
+ ): WorkspaceLearningPolicyRouterContext {
232
+ return WorkspaceLearningPolicyRouterContext.parse(effectiveMode);
233
+ }