@snaptrude/plugin-core 0.9.17 → 0.9.18-edgesetbacks-20261021.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 (219) hide show
  1. package/AGENTS.md +231 -231
  2. package/CHANGELOG.md +408 -408
  3. package/CLAUDE.md +11 -11
  4. package/api-manifest.json +1428 -712
  5. package/dist/api/analysis/daylight.d.ts +5 -5
  6. package/dist/api/analysis/solar.d.ts +2 -2
  7. package/dist/api/core/camera/index.d.ts +29 -0
  8. package/dist/api/core/camera/index.d.ts.map +1 -1
  9. package/dist/api/core/geom/create/index.d.ts +7 -1
  10. package/dist/api/core/geom/create/index.d.ts.map +1 -1
  11. package/dist/api/core/geom/update/contour.d.ts +8 -2
  12. package/dist/api/core/geom/update/contour.d.ts.map +1 -1
  13. package/dist/api/core/storeys/index.d.ts +5 -2
  14. package/dist/api/core/storeys/index.d.ts.map +1 -1
  15. package/dist/api/core/zoom/index.d.ts +13 -0
  16. package/dist/api/core/zoom/index.d.ts.map +1 -1
  17. package/dist/api/design/bim.d.ts +299 -0
  18. package/dist/api/design/bim.d.ts.map +1 -0
  19. package/dist/api/design/boolean/index.d.ts +2 -0
  20. package/dist/api/design/boolean/index.d.ts.map +1 -1
  21. package/dist/api/design/catalog.d.ts +320 -0
  22. package/dist/api/design/catalog.d.ts.map +1 -0
  23. package/dist/api/design/create/bulk-items.d.ts +65 -25
  24. package/dist/api/design/create/bulk-items.d.ts.map +1 -1
  25. package/dist/api/design/create/index.d.ts +299 -100
  26. package/dist/api/design/create/index.d.ts.map +1 -1
  27. package/dist/api/design/create/opening-fields.d.ts +13 -12
  28. package/dist/api/design/create/opening-fields.d.ts.map +1 -1
  29. package/dist/api/design/delete/index.d.ts +1 -0
  30. package/dist/api/design/delete/index.d.ts.map +1 -1
  31. package/dist/api/design/doors/index.d.ts +18 -24
  32. package/dist/api/design/doors/index.d.ts.map +1 -1
  33. package/dist/api/design/family.d.ts +813 -35
  34. package/dist/api/design/family.d.ts.map +1 -1
  35. package/dist/api/design/index.d.ts +16 -0
  36. package/dist/api/design/index.d.ts.map +1 -1
  37. package/dist/api/design/networks.d.ts +1703 -0
  38. package/dist/api/design/networks.d.ts.map +1 -0
  39. package/dist/api/design/query/grids.d.ts +2 -2
  40. package/dist/api/design/query/index.d.ts +42 -32
  41. package/dist/api/design/query/index.d.ts.map +1 -1
  42. package/dist/api/design/selection/index.d.ts +10 -10
  43. package/dist/api/design/types/index.d.ts +40 -24
  44. package/dist/api/design/types/index.d.ts.map +1 -1
  45. package/dist/api/design/update/index.d.ts +111 -6
  46. package/dist/api/design/update/index.d.ts.map +1 -1
  47. package/dist/api/design/windows/index.d.ts +8 -8
  48. package/dist/api/design/windows/index.d.ts.map +1 -1
  49. package/dist/api/entity/buildableEnvelope.d.ts +84 -2
  50. package/dist/api/entity/buildableEnvelope.d.ts.map +1 -1
  51. package/dist/api/presentation/aiInspiration.d.ts +10 -10
  52. package/dist/api/presentation/annotate.d.ts +38 -22
  53. package/dist/api/presentation/annotate.d.ts.map +1 -1
  54. package/dist/api/presentation/drawingContract.d.ts +32 -0
  55. package/dist/api/presentation/drawingContract.d.ts.map +1 -0
  56. package/dist/api/presentation/drawings.d.ts +3523 -0
  57. package/dist/api/presentation/drawings.d.ts.map +1 -0
  58. package/dist/api/presentation/export.d.ts +23 -5
  59. package/dist/api/presentation/export.d.ts.map +1 -1
  60. package/dist/api/presentation/index.d.ts +32 -12
  61. package/dist/api/presentation/index.d.ts.map +1 -1
  62. package/dist/api/presentation/placedViews.d.ts +106 -6
  63. package/dist/api/presentation/placedViews.d.ts.map +1 -1
  64. package/dist/api/presentation/shapes.d.ts +2 -2
  65. package/dist/api/presentation/sheets.d.ts +175 -19
  66. package/dist/api/presentation/sheets.d.ts.map +1 -1
  67. package/dist/api/presentation/viewPresets.d.ts +222 -0
  68. package/dist/api/presentation/viewPresets.d.ts.map +1 -0
  69. package/dist/api/presentation/views.d.ts +141 -8
  70. package/dist/api/presentation/views.d.ts.map +1 -1
  71. package/dist/api/presentation/walkthroughs.d.ts +6 -6
  72. package/dist/errors/codes.d.ts +3 -1
  73. package/dist/errors/codes.d.ts.map +1 -1
  74. package/dist/index.cjs +3831 -2444
  75. package/dist/index.cjs.map +1 -1
  76. package/dist/index.js +3705 -2444
  77. package/dist/index.js.map +1 -1
  78. package/package.json +1 -1
  79. package/scripts/check-dist-fresh.mjs +22 -22
  80. package/scripts/generate-manifest.mjs +243 -238
  81. package/scripts/generate-manifest.test.mjs +303 -303
  82. package/src/api/analysis/daylight.ts +470 -470
  83. package/src/api/analysis/heatmaps.ts +683 -683
  84. package/src/api/analysis/illuminance.ts +155 -155
  85. package/src/api/analysis/index.ts +61 -61
  86. package/src/api/analysis/shadows.ts +183 -183
  87. package/src/api/analysis/solar.ts +237 -237
  88. package/src/api/analysis/sunlightHours.ts +211 -211
  89. package/src/api/analysis/sunpath.ts +83 -83
  90. package/src/api/analysis/weather.ts +179 -179
  91. package/src/api/core/buildings.ts +485 -485
  92. package/src/api/core/camera/index.ts +696 -667
  93. package/src/api/core/comment/index.ts +376 -376
  94. package/src/api/core/geom/create/index.ts +2139 -2133
  95. package/src/api/core/geom/delete/index.ts +84 -84
  96. package/src/api/core/geom/index.ts +35 -35
  97. package/src/api/core/geom/query/arc.ts +169 -169
  98. package/src/api/core/geom/query/brep.ts +621 -621
  99. package/src/api/core/geom/query/circle.ts +404 -404
  100. package/src/api/core/geom/query/contour.ts +540 -540
  101. package/src/api/core/geom/query/curve.ts +1102 -1102
  102. package/src/api/core/geom/query/edge.ts +130 -130
  103. package/src/api/core/geom/query/face.ts +508 -508
  104. package/src/api/core/geom/query/halfedge.ts +210 -210
  105. package/src/api/core/geom/query/index.ts +63 -63
  106. package/src/api/core/geom/query/profile.ts +473 -473
  107. package/src/api/core/geom/query/vertex.ts +205 -205
  108. package/src/api/core/geom/update/contour.ts +323 -317
  109. package/src/api/core/geom/update/curve.ts +209 -209
  110. package/src/api/core/geom/update/index.ts +29 -29
  111. package/src/api/core/geom/update/profile.ts +379 -379
  112. package/src/api/core/groups.ts +521 -521
  113. package/src/api/core/handles/index.ts +234 -234
  114. package/src/api/core/history/index.ts +84 -84
  115. package/src/api/core/index.ts +99 -99
  116. package/src/api/core/io/export/index.ts +126 -126
  117. package/src/api/core/io/import/index.ts +504 -504
  118. package/src/api/core/io/index.ts +42 -42
  119. package/src/api/core/io/job/index.ts +140 -140
  120. package/src/api/core/io/query/index.ts +71 -71
  121. package/src/api/core/io/terrain/index.ts +360 -360
  122. package/src/api/core/io/underlay/index.ts +705 -705
  123. package/src/api/core/layers.ts +540 -540
  124. package/src/api/core/math/index.ts +20 -20
  125. package/src/api/core/math/quat.ts +172 -172
  126. package/src/api/core/math/vec3.ts +179 -179
  127. package/src/api/core/mode/index.ts +108 -108
  128. package/src/api/core/project/index.ts +479 -479
  129. package/src/api/core/proposals/index.ts +570 -570
  130. package/src/api/core/storeys/index.ts +311 -308
  131. package/src/api/core/storeys/layers.ts +339 -339
  132. package/src/api/core/tags.ts +911 -911
  133. package/src/api/core/units/index.ts +164 -164
  134. package/src/api/core/user.ts +46 -46
  135. package/src/api/core/zoom/index.ts +64 -51
  136. package/src/api/design/bim.ts +210 -0
  137. package/src/api/design/boolean/index.ts +181 -179
  138. package/src/api/design/catalog.ts +203 -0
  139. package/src/api/design/create/bulk-items.ts +294 -254
  140. package/src/api/design/create/grids.ts +137 -137
  141. package/src/api/design/create/index.ts +2178 -1980
  142. package/src/api/design/create/opening-fields.ts +40 -37
  143. package/src/api/design/delete/index.ts +75 -74
  144. package/src/api/design/dimensions.ts +453 -453
  145. package/src/api/design/doors/index.ts +516 -500
  146. package/src/api/design/edit/index.ts +54 -54
  147. package/src/api/design/erase/index.ts +151 -151
  148. package/src/api/design/family.ts +1342 -704
  149. package/src/api/design/furniture/index.ts +319 -319
  150. package/src/api/design/grids.ts +237 -237
  151. package/src/api/design/index.ts +304 -274
  152. package/src/api/design/lock.ts +69 -69
  153. package/src/api/design/materials/index.ts +608 -608
  154. package/src/api/design/networks.ts +607 -0
  155. package/src/api/design/query/geometry/index.ts +319 -319
  156. package/src/api/design/query/grids.ts +197 -197
  157. package/src/api/design/query/index.ts +1236 -1226
  158. package/src/api/design/query/referenceLines.ts +52 -52
  159. package/src/api/design/query/spaces.ts +275 -275
  160. package/src/api/design/selection/index.ts +273 -273
  161. package/src/api/design/shared.ts +40 -40
  162. package/src/api/design/transform/index.ts +254 -254
  163. package/src/api/design/types/index.ts +163 -156
  164. package/src/api/design/update/index.ts +1096 -983
  165. package/src/api/design/visibility.ts +143 -143
  166. package/src/api/design/windows/index.ts +351 -333
  167. package/src/api/entity/buildableEnvelope.ts +397 -322
  168. package/src/api/entity/index.ts +30 -30
  169. package/src/api/entity/referenceLine.ts +235 -235
  170. package/src/api/entity/space.ts +612 -612
  171. package/src/api/entity/story.ts +517 -517
  172. package/src/api/index.ts +47 -47
  173. package/src/api/presentation/aiInspiration.ts +1116 -1116
  174. package/src/api/presentation/annotate.ts +417 -385
  175. package/src/api/presentation/camera.ts +289 -289
  176. package/src/api/presentation/diagrams.ts +194 -194
  177. package/src/api/presentation/drawingContract.ts +70 -0
  178. package/src/api/presentation/drawings.ts +1179 -0
  179. package/src/api/presentation/export.ts +134 -108
  180. package/src/api/presentation/import.ts +159 -159
  181. package/src/api/presentation/index.ts +160 -135
  182. package/src/api/presentation/placedViews.ts +1211 -1120
  183. package/src/api/presentation/sections.ts +420 -420
  184. package/src/api/presentation/shapes.ts +274 -274
  185. package/src/api/presentation/sheets.ts +746 -585
  186. package/src/api/presentation/slideshow.ts +134 -134
  187. package/src/api/presentation/tables.ts +84 -84
  188. package/src/api/presentation/viewPresets.ts +241 -0
  189. package/src/api/presentation/views.ts +742 -673
  190. package/src/api/presentation/walkthroughs.ts +1201 -1201
  191. package/src/api/program/adjacency.ts +164 -164
  192. package/src/api/program/areas.ts +408 -408
  193. package/src/api/program/classification.ts +138 -138
  194. package/src/api/program/cores.ts +83 -83
  195. package/src/api/program/departments.ts +517 -517
  196. package/src/api/program/index.ts +73 -73
  197. package/src/api/program/labels.ts +332 -332
  198. package/src/api/program/layout.ts +422 -422
  199. package/src/api/program/metadata.ts +364 -364
  200. package/src/api/program/metrics.ts +120 -120
  201. package/src/api/program/site.ts +748 -748
  202. package/src/api/program/spreadsheet.ts +2698 -2698
  203. package/src/api/workspace/index.ts +612 -612
  204. package/src/errors/codes.ts +143 -136
  205. package/src/errors/envelope.ts +75 -75
  206. package/src/errors/index.ts +21 -21
  207. package/src/errors/plugin-error.ts +134 -134
  208. package/src/handles.ts +297 -297
  209. package/src/host-utils.ts +67 -67
  210. package/src/index.ts +7 -7
  211. package/src/massParameters.ops.ts +246 -246
  212. package/src/massParameters.ts +427 -427
  213. package/src/types.ts +16 -16
  214. package/test/drawingContract.test.mjs +288 -0
  215. package/test/errors.test.mjs +185 -184
  216. package/test/massParameters.test.mjs +952 -952
  217. package/test/presentationViewSettings.test.mjs +85 -0
  218. package/tsconfig.json +22 -22
  219. package/tsup.config.ts +12 -12
@@ -1,1116 +1,1116 @@
1
- import * as z from "zod"
2
- import type { PluginApiReturn } from "../../types"
3
-
4
- const JsonPrimitive = z.union([z.string(), z.number(), z.boolean(), z.null()])
5
- type JsonValue =
6
- | z.infer<typeof JsonPrimitive>
7
- | JsonValue[]
8
- | { [key: string]: JsonValue }
9
- const JsonValue: z.ZodType<JsonValue> = z.lazy(() =>
10
- z.union([JsonPrimitive, z.array(JsonValue), z.record(z.string(), JsonValue)]),
11
- )
12
-
13
- export const PluginAIInspirationRunMode = z.enum(["blocking", "job"])
14
- export type PluginAIInspirationRunMode = z.infer<
15
- typeof PluginAIInspirationRunMode
16
- >
17
-
18
- export const PluginAIInspirationOutputKind = z.enum([
19
- "source",
20
- "image",
21
- "video",
22
- ])
23
- export type PluginAIInspirationOutputKind = z.infer<
24
- typeof PluginAIInspirationOutputKind
25
- >
26
-
27
- export const PluginAIInspirationModelOutput = z.enum(["image", "video"])
28
- export type PluginAIInspirationModelOutput = z.infer<
29
- typeof PluginAIInspirationModelOutput
30
- >
31
-
32
- export const PluginAIInspirationRuntimeProvider = z.enum(["gpt", "fal"])
33
- export type PluginAIInspirationRuntimeProvider = z.infer<
34
- typeof PluginAIInspirationRuntimeProvider
35
- >
36
-
37
- export const PluginAIInspirationPromptStrategy = z.enum([
38
- "gpt-image",
39
- "fal-image",
40
- "fal-video",
41
- ])
42
- export type PluginAIInspirationPromptStrategy = z.infer<
43
- typeof PluginAIInspirationPromptStrategy
44
- >
45
-
46
- export const PluginAIInspirationShapeKind = z.enum(["image", "view", "video"])
47
- export type PluginAIInspirationShapeKind = z.infer<
48
- typeof PluginAIInspirationShapeKind
49
- >
50
-
51
- export const PluginAIInspirationVideoMode = z.enum([
52
- "animate",
53
- "references",
54
- "keyframes",
55
- ])
56
- export type PluginAIInspirationVideoMode = z.infer<
57
- typeof PluginAIInspirationVideoMode
58
- >
59
-
60
- export const PluginAIInspirationVideoMotion = z.enum([
61
- "auto",
62
- "slow-dolly",
63
- "subtle-orbit",
64
- "reveal",
65
- ])
66
- export type PluginAIInspirationVideoMotion = z.infer<
67
- typeof PluginAIInspirationVideoMotion
68
- >
69
-
70
- export const PluginAIInspirationVideoDuration = z.enum(["4s", "6s", "8s"])
71
- export type PluginAIInspirationVideoDuration = z.infer<
72
- typeof PluginAIInspirationVideoDuration
73
- >
74
-
75
- export const PluginAIInspirationJobStatus = z.enum([
76
- "queued",
77
- "running",
78
- "completed",
79
- "failed",
80
- "cancelled",
81
- ])
82
- export type PluginAIInspirationJobStatus = z.infer<
83
- typeof PluginAIInspirationJobStatus
84
- >
85
-
86
- export const PluginAIInspirationWorkflowRunState = z.enum([
87
- "current",
88
- "stale",
89
- "running",
90
- "failed",
91
- "superseded",
92
- ])
93
- export type PluginAIInspirationWorkflowRunState = z.infer<
94
- typeof PluginAIInspirationWorkflowRunState
95
- >
96
-
97
- export const PluginAIInspirationRegionHint = z.object({
98
- x: z.number().finite(),
99
- y: z.number().finite(),
100
- w: z.number().finite().positive(),
101
- h: z.number().finite().positive(),
102
- })
103
- export type PluginAIInspirationRegionHint = z.infer<
104
- typeof PluginAIInspirationRegionHint
105
- >
106
-
107
- export const PluginAIInspirationPoint = z.object({
108
- x: z.number().finite(),
109
- y: z.number().finite(),
110
- })
111
- export type PluginAIInspirationPoint = z.infer<typeof PluginAIInspirationPoint>
112
-
113
- export const PluginAIInspirationTextAnnotation = z.object({
114
- text: z.string().min(1),
115
- x: z.number().finite().optional(),
116
- y: z.number().finite().optional(),
117
- })
118
- export type PluginAIInspirationTextAnnotation = z.infer<
119
- typeof PluginAIInspirationTextAnnotation
120
- >
121
-
122
- export const PluginAIInspirationSketchGuidance = z.object({
123
- visualShapeIds: z.array(z.string()).optional(),
124
- textAnnotations: z.array(PluginAIInspirationTextAnnotation).optional(),
125
- })
126
- export type PluginAIInspirationSketchGuidance = z.infer<
127
- typeof PluginAIInspirationSketchGuidance
128
- >
129
-
130
- export const PluginAIInspirationSiteOptions = z.object({
131
- includeSatellite: z.boolean().optional(),
132
- includeStreetView: z.boolean().optional(),
133
- includeAerial: z.boolean().optional(),
134
- aerialBearing: z.number().finite().optional(),
135
- aerialPitch: z.number().finite().optional(),
136
- selectedDiagramIds: z.array(z.string()).optional(),
137
- location: z
138
- .object({
139
- lat: z.number().finite(),
140
- lng: z.number().finite(),
141
- })
142
- .optional(),
143
- })
144
- export type PluginAIInspirationSiteOptions = z.infer<
145
- typeof PluginAIInspirationSiteOptions
146
- >
147
-
148
- export const PluginAIInspirationAppliedPreset = z.object({
149
- source: z.enum(["curated", "user"]),
150
- presetId: z.string().min(1),
151
- name: z.string().min(1),
152
- savedPresetKind: z.enum(["prompt", "style"]).optional(),
153
- stylePrompt: z.string().optional(),
154
- modelId: z.string().optional(),
155
- referenceImages: z
156
- .array(
157
- z.object({
158
- url: z.string().min(1),
159
- label: z.string().optional(),
160
- weight: z.number().finite().optional(),
161
- }),
162
- )
163
- .optional(),
164
- siteDefaults: z
165
- .object({
166
- includeSatellite: z.boolean().optional(),
167
- includeStreetView: z.boolean().optional(),
168
- includeAerial: z.boolean().optional(),
169
- })
170
- .optional(),
171
- })
172
- export type PluginAIInspirationAppliedPreset = z.infer<
173
- typeof PluginAIInspirationAppliedPreset
174
- >
175
-
176
- export const PluginAIInspirationVideoOptions = z.object({
177
- mode: PluginAIInspirationVideoMode.optional(),
178
- endFrameShapeId: z.string().optional(),
179
- motion: PluginAIInspirationVideoMotion.optional(),
180
- duration: PluginAIInspirationVideoDuration.optional(),
181
- })
182
- export type PluginAIInspirationVideoOptions = z.infer<
183
- typeof PluginAIInspirationVideoOptions
184
- >
185
-
186
- export const PluginAIInspirationModel = z.object({
187
- id: z.string(),
188
- label: z.string(),
189
- supportsMultiImage: z.boolean(),
190
- output: PluginAIInspirationModelOutput,
191
- isDefault: z.boolean().optional(),
192
- })
193
- export type PluginAIInspirationModel = z.infer<typeof PluginAIInspirationModel>
194
-
195
- export const PluginAIInspirationModelCapability = z.object({
196
- id: z.string(),
197
- output: PluginAIInspirationModelOutput,
198
- provider: PluginAIInspirationRuntimeProvider,
199
- supportsRegionEdit: z.boolean(),
200
- supportsReferenceImages: z.boolean(),
201
- supportsStylePresets: z.boolean(),
202
- supportsSiteContext: z.boolean(),
203
- supportsSketchGuidance: z.boolean(),
204
- supportsKeyframes: z.boolean(),
205
- maxExtraImages: z.number().int().nonnegative(),
206
- promptStrategy: PluginAIInspirationPromptStrategy,
207
- })
208
- export type PluginAIInspirationModelCapability = z.infer<
209
- typeof PluginAIInspirationModelCapability
210
- >
211
-
212
- export const PluginAIInspirationListModelsResult = z.object({
213
- defaultModelId: z.string(),
214
- models: z.array(PluginAIInspirationModel),
215
- })
216
- export type PluginAIInspirationListModelsResult = z.infer<
217
- typeof PluginAIInspirationListModelsResult
218
- >
219
-
220
- export const PluginAIInspirationGetModelCapabilitiesArgs = z.object({
221
- modelId: z.string().min(1),
222
- })
223
- export type PluginAIInspirationGetModelCapabilitiesArgs = z.infer<
224
- typeof PluginAIInspirationGetModelCapabilitiesArgs
225
- >
226
-
227
- export const PluginAIInspirationGetModelCapabilitiesResult = z.object({
228
- capability: PluginAIInspirationModelCapability,
229
- })
230
- export type PluginAIInspirationGetModelCapabilitiesResult = z.infer<
231
- typeof PluginAIInspirationGetModelCapabilitiesResult
232
- >
233
-
234
- export const PluginAIInspirationShapeRef = z.object({
235
- shapeId: z.string(),
236
- assetId: z.string().optional(),
237
- kind: PluginAIInspirationShapeKind,
238
- name: z.string().optional(),
239
- width: z.number().finite().optional(),
240
- height: z.number().finite().optional(),
241
- outputType: PluginAIInspirationOutputKind.optional(),
242
- sourceUrl: z.string().optional(),
243
- })
244
- export type PluginAIInspirationShapeRef = z.infer<
245
- typeof PluginAIInspirationShapeRef
246
- >
247
-
248
- export const PluginAIInspirationListSourcesArgs = z.object({
249
- includeGenerated: z.boolean().optional(),
250
- includeSourceUrl: z.boolean().optional(),
251
- })
252
- export type PluginAIInspirationListSourcesArgs = z.infer<
253
- typeof PluginAIInspirationListSourcesArgs
254
- >
255
-
256
- export const PluginAIInspirationListSourcesResult = z.object({
257
- sources: z.array(PluginAIInspirationShapeRef),
258
- })
259
- export type PluginAIInspirationListSourcesResult = z.infer<
260
- typeof PluginAIInspirationListSourcesResult
261
- >
262
-
263
- export const PluginAIInspirationGetSelectionResult = z.object({
264
- selectedShapeIds: z.array(z.string()),
265
- sources: z.array(PluginAIInspirationShapeRef),
266
- })
267
- export type PluginAIInspirationGetSelectionResult = z.infer<
268
- typeof PluginAIInspirationGetSelectionResult
269
- >
270
-
271
- export const PluginAIInspirationPresetReferenceImage = z.object({
272
- url: z.string(),
273
- label: z.string().optional(),
274
- weight: z.number().finite().optional(),
275
- })
276
- export type PluginAIInspirationPresetReferenceImage = z.infer<
277
- typeof PluginAIInspirationPresetReferenceImage
278
- >
279
-
280
- export const PluginAIInspirationPreset = z.object({
281
- id: z.string(),
282
- name: z.string(),
283
- source: z.enum(["curated", "user"]),
284
- modelId: z.string(),
285
- categoryId: z.string().optional(),
286
- categoryLabel: z.string().optional(),
287
- description: z.string().optional(),
288
- previewImageUrl: z.string().optional(),
289
- prompt: z.string().optional(),
290
- stylePrompt: z.string().optional(),
291
- tags: z.array(z.string()).optional(),
292
- referenceImages: z.array(PluginAIInspirationPresetReferenceImage).optional(),
293
- siteDefaults: PluginAIInspirationAppliedPreset.shape.siteDefaults.optional(),
294
- })
295
- export type PluginAIInspirationPreset = z.infer<
296
- typeof PluginAIInspirationPreset
297
- >
298
-
299
- export const PluginAIInspirationPresetCategory = z.object({
300
- id: z.string(),
301
- label: z.string(),
302
- description: z.string().optional(),
303
- })
304
- export type PluginAIInspirationPresetCategory = z.infer<
305
- typeof PluginAIInspirationPresetCategory
306
- >
307
-
308
- export const PluginAIInspirationGetPresetCatalogResult = z.object({
309
- categories: z.array(PluginAIInspirationPresetCategory),
310
- presets: z.array(PluginAIInspirationPreset),
311
- })
312
- export type PluginAIInspirationGetPresetCatalogResult = z.infer<
313
- typeof PluginAIInspirationGetPresetCatalogResult
314
- >
315
-
316
- export const PluginAIInspirationOutput = z.object({
317
- outputType: z.enum(["image", "video"]),
318
- shapeId: z.string(),
319
- assetId: z.string(),
320
- outputUrl: z.string().optional(),
321
- position: PluginAIInspirationPoint.optional(),
322
- })
323
- export type PluginAIInspirationOutput = z.infer<
324
- typeof PluginAIInspirationOutput
325
- >
326
-
327
- export const PluginAIInspirationDebugSummary = z.record(z.string(), JsonValue)
328
- export type PluginAIInspirationDebugSummary = z.infer<
329
- typeof PluginAIInspirationDebugSummary
330
- >
331
-
332
- export const PluginAIInspirationRunMetadata = z.object({
333
- geometryFidelity: z.string().optional(),
334
- debugSummary: PluginAIInspirationDebugSummary.optional(),
335
- streetViewComposite: z
336
- .object({
337
- used: z.boolean(),
338
- renderMode: z.enum(["prompt_refs_default", "masked_composite_pilot"]),
339
- backgroundLabel: z.string().optional(),
340
- })
341
- .optional(),
342
- })
343
- export type PluginAIInspirationRunMetadata = z.infer<
344
- typeof PluginAIInspirationRunMetadata
345
- >
346
-
347
- export const PluginAIInspirationGenerateArgs = z.object({
348
- sourceShapeId: z.string().min(1),
349
- prompt: z.string().min(1).max(8000),
350
- modelId: z.string().optional(),
351
- referenceShapeIds: z.array(z.string()).max(12).optional(),
352
- referenceStrength: z.enum(["low", "medium", "high"]).optional(),
353
- appliedPreset: PluginAIInspirationAppliedPreset.optional(),
354
- site: PluginAIInspirationSiteOptions.optional(),
355
- regionHint: PluginAIInspirationRegionHint.optional(),
356
- sketchGuidance: PluginAIInspirationSketchGuidance.optional(),
357
- video: PluginAIInspirationVideoOptions.optional(),
358
- runMode: PluginAIInspirationRunMode.optional(),
359
- })
360
- export type PluginAIInspirationGenerateArgs = z.infer<
361
- typeof PluginAIInspirationGenerateArgs
362
- >
363
-
364
- export const PluginAIInspirationRunResult = z.object({
365
- jobId: z.string().optional(),
366
- output: PluginAIInspirationOutput.optional(),
367
- outputs: z.array(PluginAIInspirationOutput).optional(),
368
- metadata: PluginAIInspirationRunMetadata.optional(),
369
- })
370
- export type PluginAIInspirationRunResult = z.infer<
371
- typeof PluginAIInspirationRunResult
372
- >
373
-
374
- export const PluginAIInspirationRefineArgs = z.object({
375
- sourceShapeId: z.string().min(1),
376
- upscaleFactor: z
377
- .union([z.literal(1.5), z.literal(2), z.literal(4)])
378
- .optional(),
379
- runMode: PluginAIInspirationRunMode.optional(),
380
- })
381
- export type PluginAIInspirationRefineArgs = z.infer<
382
- typeof PluginAIInspirationRefineArgs
383
- >
384
-
385
- export const PluginAIInspirationJobProgress = z.object({
386
- currentStep: z.number().int().nonnegative().optional(),
387
- totalSteps: z.number().int().nonnegative().optional(),
388
- message: z.string().optional(),
389
- })
390
- export type PluginAIInspirationJobProgress = z.infer<
391
- typeof PluginAIInspirationJobProgress
392
- >
393
-
394
- export const PluginAIInspirationJob = z.object({
395
- jobId: z.string(),
396
- status: PluginAIInspirationJobStatus,
397
- createdAt: z.number(),
398
- updatedAt: z.number(),
399
- completedAt: z.number().optional(),
400
- method: z.string(),
401
- progress: PluginAIInspirationJobProgress.optional(),
402
- result: PluginAIInspirationRunResult.optional(),
403
- error: z.string().optional(),
404
- })
405
- export type PluginAIInspirationJob = z.infer<typeof PluginAIInspirationJob>
406
-
407
- export const PluginAIInspirationJobArgs = z.object({
408
- jobId: z.string().min(1),
409
- })
410
- export type PluginAIInspirationJobArgs = z.infer<
411
- typeof PluginAIInspirationJobArgs
412
- >
413
-
414
- export const PluginAIInspirationGetJobResult = z.object({
415
- job: PluginAIInspirationJob,
416
- })
417
- export type PluginAIInspirationGetJobResult = z.infer<
418
- typeof PluginAIInspirationGetJobResult
419
- >
420
-
421
- export const PluginAIInspirationCancelJobResult = z.object({
422
- job: PluginAIInspirationJob,
423
- })
424
- export type PluginAIInspirationCancelJobResult = z.infer<
425
- typeof PluginAIInspirationCancelJobResult
426
- >
427
-
428
- export const PluginAIInspirationListJobsResult = z.object({
429
- jobs: z.array(PluginAIInspirationJob),
430
- })
431
- export type PluginAIInspirationListJobsResult = z.infer<
432
- typeof PluginAIInspirationListJobsResult
433
- >
434
-
435
- export const PluginAIInspirationWorkflowVideoConfig = z.object({
436
- mode: z.string().optional(),
437
- motion: z.string().optional(),
438
- duration: z.string().optional(),
439
- endFrameShapeId: z.string().optional(),
440
- })
441
- export type PluginAIInspirationWorkflowVideoConfig = z.infer<
442
- typeof PluginAIInspirationWorkflowVideoConfig
443
- >
444
-
445
- export const PluginAIInspirationGenerationInputSnapshot = z.object({
446
- version: z.literal(1),
447
- meta: z.record(z.string(), JsonValue),
448
- regionHint: PluginAIInspirationRegionHint.optional(),
449
- sketchGuidance: z.record(z.string(), JsonValue).optional(),
450
- sourceCameraHeading: z.number().finite().optional(),
451
- })
452
- export type PluginAIInspirationGenerationInputSnapshot = z.infer<
453
- typeof PluginAIInspirationGenerationInputSnapshot
454
- >
455
-
456
- export const PluginAIInspirationWorkflowOperation = z.object({
457
- type: z.enum(["generate-image", "refine", "generate-video"]),
458
- label: z.string(),
459
- prompt: z.string().optional(),
460
- modelId: z.string().optional(),
461
- presetId: z.string().optional(),
462
- presetName: z.string().optional(),
463
- refineFactor: z.number().finite().optional(),
464
- sourceRole: z.enum(["primary", "end-frame"]).optional(),
465
- video: PluginAIInspirationWorkflowVideoConfig.optional(),
466
- generationInput: PluginAIInspirationGenerationInputSnapshot.optional(),
467
- })
468
- export type PluginAIInspirationWorkflowOperation = z.infer<
469
- typeof PluginAIInspirationWorkflowOperation
470
- >
471
-
472
- export const PluginAIInspirationWorkflowNode = z.object({
473
- id: z.string(),
474
- shapeId: z.string(),
475
- assetId: z.string().optional(),
476
- kind: PluginAIInspirationOutputKind,
477
- state: z.string(),
478
- runState: PluginAIInspirationWorkflowRunState.optional(),
479
- staleReason: z.string().optional(),
480
- incomingEdgeIds: z.array(z.string()),
481
- outgoingEdgeIds: z.array(z.string()),
482
- createdAt: z.number(),
483
- updatedAt: z.number(),
484
- })
485
- export type PluginAIInspirationWorkflowNode = z.infer<
486
- typeof PluginAIInspirationWorkflowNode
487
- >
488
-
489
- export const PluginAIInspirationWorkflowEdge = z.object({
490
- id: z.string(),
491
- sourceNodeId: z.string(),
492
- targetNodeId: z.string(),
493
- arrowShapeId: z.string().optional(),
494
- operation: PluginAIInspirationWorkflowOperation,
495
- state: z.string(),
496
- runState: PluginAIInspirationWorkflowRunState.optional(),
497
- staleReason: z.string().optional(),
498
- supersededByEdgeId: z.string().optional(),
499
- createdAt: z.number(),
500
- updatedAt: z.number(),
501
- })
502
- export type PluginAIInspirationWorkflowEdge = z.infer<
503
- typeof PluginAIInspirationWorkflowEdge
504
- >
505
-
506
- export const PluginAIInspirationWorkflow = z.object({
507
- id: z.string(),
508
- rootNodeIds: z.array(z.string()),
509
- nodeIds: z.array(z.string()),
510
- edgeIds: z.array(z.string()),
511
- nodes: z.record(z.string(), PluginAIInspirationWorkflowNode),
512
- edges: z.record(z.string(), PluginAIInspirationWorkflowEdge),
513
- createdAt: z.number(),
514
- updatedAt: z.number(),
515
- })
516
- export type PluginAIInspirationWorkflow = z.infer<
517
- typeof PluginAIInspirationWorkflow
518
- >
519
-
520
- export const PluginAIInspirationGetWorkflowForShapeArgs = z.object({
521
- shapeId: z.string().min(1),
522
- })
523
- export type PluginAIInspirationGetWorkflowForShapeArgs = z.infer<
524
- typeof PluginAIInspirationGetWorkflowForShapeArgs
525
- >
526
-
527
- export const PluginAIInspirationGetWorkflowForShapeResult = z.object({
528
- workflow: PluginAIInspirationWorkflow.nullable(),
529
- node: PluginAIInspirationWorkflowNode.nullable(),
530
- })
531
- export type PluginAIInspirationGetWorkflowForShapeResult = z.infer<
532
- typeof PluginAIInspirationGetWorkflowForShapeResult
533
- >
534
-
535
- export const PluginAIInspirationRerunPlanResult = z.discriminatedUnion(
536
- "status",
537
- [
538
- z.object({
539
- status: z.literal("ready"),
540
- workflowId: z.string(),
541
- sourceNode: PluginAIInspirationWorkflowNode,
542
- edgeIds: z.array(z.string()),
543
- edges: z.array(PluginAIInspirationWorkflowEdge),
544
- recipe: z.lazy(() => PluginAIInspirationRecipe),
545
- needsEndFrame: z.boolean(),
546
- defaultEndFrameShapeId: z.string().nullable(),
547
- }),
548
- z.object({
549
- status: z.literal("unavailable"),
550
- reason: z.enum([
551
- "not-in-workflow",
552
- "source-only",
553
- "running",
554
- "missing-input",
555
- ]),
556
- }),
557
- ],
558
- )
559
- export type PluginAIInspirationRerunPlanResult = z.infer<
560
- typeof PluginAIInspirationRerunPlanResult
561
- >
562
-
563
- export const PluginAIInspirationRerunSelectedBranchArgs = z.object({
564
- shapeId: z.string().min(1),
565
- endFrameShapeId: z.string().optional(),
566
- runMode: PluginAIInspirationRunMode.optional(),
567
- })
568
- export type PluginAIInspirationRerunSelectedBranchArgs = z.infer<
569
- typeof PluginAIInspirationRerunSelectedBranchArgs
570
- >
571
-
572
- export const PluginAIInspirationRecipeSlot = z.object({
573
- id: z.string(),
574
- type: z.enum(["source-image", "end-frame"]),
575
- label: z.string(),
576
- required: z.boolean(),
577
- })
578
- export type PluginAIInspirationRecipeSlot = z.infer<
579
- typeof PluginAIInspirationRecipeSlot
580
- >
581
-
582
- export const PluginAIInspirationRecipeStep = z.object({
583
- id: z.string(),
584
- operation: PluginAIInspirationWorkflowOperation,
585
- outputKind: z.enum(["image", "video"]),
586
- })
587
- export type PluginAIInspirationRecipeStep = z.infer<
588
- typeof PluginAIInspirationRecipeStep
589
- >
590
-
591
- export const PluginAIInspirationRecipeDraft = z.object({
592
- name: z.string(),
593
- summary: z.string(),
594
- slots: z.array(PluginAIInspirationRecipeSlot),
595
- steps: z.array(PluginAIInspirationRecipeStep).min(1).max(20),
596
- outputKind: z.enum(["image", "video"]),
597
- thumbnailUrl: z.string().optional(),
598
- })
599
- export type PluginAIInspirationRecipeDraft = z.infer<
600
- typeof PluginAIInspirationRecipeDraft
601
- >
602
-
603
- export const PluginAIInspirationRecipe: z.ZodType<
604
- PluginAIInspirationRecipeDraft & {
605
- version: 1
606
- id: string
607
- fingerprint?: string
608
- createdAt: number
609
- updatedAt: number
610
- }
611
- > = PluginAIInspirationRecipeDraft.extend({
612
- version: z.literal(1),
613
- id: z.string(),
614
- fingerprint: z.string().optional(),
615
- createdAt: z.number(),
616
- updatedAt: z.number(),
617
- })
618
- export type PluginAIInspirationRecipe = z.infer<
619
- typeof PluginAIInspirationRecipe
620
- >
621
-
622
- export const PluginAIInspirationExtractionResult = z.discriminatedUnion(
623
- "status",
624
- [
625
- z.object({
626
- status: z.literal("ready"),
627
- draft: PluginAIInspirationRecipeDraft,
628
- }),
629
- z.object({
630
- status: z.literal("unavailable"),
631
- reason: z.enum([
632
- "not-in-workflow",
633
- "source-only",
634
- "missing-workflow",
635
- "missing-node",
636
- "missing-input",
637
- "invalid-workflow",
638
- ]),
639
- }),
640
- ],
641
- )
642
- export type PluginAIInspirationExtractionResult = z.infer<
643
- typeof PluginAIInspirationExtractionResult
644
- >
645
-
646
- export const PluginAIInspirationListRecipesResult = z.object({
647
- recipes: z.array(PluginAIInspirationRecipe),
648
- })
649
- export type PluginAIInspirationListRecipesResult = z.infer<
650
- typeof PluginAIInspirationListRecipesResult
651
- >
652
-
653
- export const PluginAIInspirationSaveRecipeArgs = z.object({
654
- draft: PluginAIInspirationRecipeDraft,
655
- name: z.string().min(1),
656
- })
657
- export type PluginAIInspirationSaveRecipeArgs = z.infer<
658
- typeof PluginAIInspirationSaveRecipeArgs
659
- >
660
-
661
- export const PluginAIInspirationSaveRecipeResult = z.discriminatedUnion(
662
- "status",
663
- [
664
- z.object({ status: z.literal("saved"), recipe: PluginAIInspirationRecipe }),
665
- z.object({
666
- status: z.literal("duplicate"),
667
- recipe: PluginAIInspirationRecipe,
668
- }),
669
- z.object({ status: z.literal("invalid-name"), recipe: z.null() }),
670
- z.object({ status: z.literal("failed"), recipe: z.null() }),
671
- ],
672
- )
673
- export type PluginAIInspirationSaveRecipeResult = z.infer<
674
- typeof PluginAIInspirationSaveRecipeResult
675
- >
676
-
677
- export const PluginAIInspirationDeleteRecipeArgs = z.object({
678
- recipeId: z.string().min(1),
679
- })
680
- export type PluginAIInspirationDeleteRecipeArgs = z.infer<
681
- typeof PluginAIInspirationDeleteRecipeArgs
682
- >
683
-
684
- export const PluginAIInspirationDeleteRecipeResult = z.object({
685
- deleted: z.boolean(),
686
- })
687
- export type PluginAIInspirationDeleteRecipeResult = z.infer<
688
- typeof PluginAIInspirationDeleteRecipeResult
689
- >
690
-
691
- export const PluginAIInspirationExtractRecipeFromShapeArgs = z.object({
692
- shapeId: z.string().min(1),
693
- })
694
- export type PluginAIInspirationExtractRecipeFromShapeArgs = z.infer<
695
- typeof PluginAIInspirationExtractRecipeFromShapeArgs
696
- >
697
-
698
- export const PluginAIInspirationRunRecipeArgs = z.object({
699
- recipeId: z.string().optional(),
700
- recipe: PluginAIInspirationRecipe.optional(),
701
- slotShapeIds: z.record(z.string(), z.string()),
702
- runMode: PluginAIInspirationRunMode.optional(),
703
- })
704
- export type PluginAIInspirationRunRecipeArgs = z.infer<
705
- typeof PluginAIInspirationRunRecipeArgs
706
- >
707
-
708
- /**
709
- * Present-mode AI Inspiration APIs.
710
- *
711
- * These APIs operate on Present canvas shape IDs and inherit the current user's
712
- * AI quota. They create outputs on the Present canvas; pure backend generation
713
- * without canvas output is intentionally out of scope.
714
- *
715
- * Long-running generations can be started with `runMode: "job"` and tracked via
716
- * {@linkcode PluginPresentationAIInspirationApi.getJob} /
717
- * {@linkcode PluginPresentationAIInspirationApi.listJobs}; the default
718
- * `"blocking"` mode resolves with the canvas outputs directly.
719
- *
720
- * Accessed via `snaptrude.presentation.aiInspiration`.
721
- */
722
- export abstract class PluginPresentationAIInspirationApi {
723
- constructor() {}
724
-
725
- /**
726
- * List AI Inspiration models that can be used for generation.
727
- *
728
- * @returns The default model ID and available model descriptors.
729
- *
730
- * @examplePrompt What AI inspiration models can I use?
731
- * @examplePrompt List the available image and video models
732
- * @examplePrompt Which generation model is the default?
733
- *
734
- * # Example
735
- * ```ts
736
- * const { defaultModelId, models } = await snaptrude.presentation.aiInspiration.listModels()
737
- * const videoModels = models.filter((m) => m.output === "video")
738
- * console.log(defaultModelId, videoModels.map((m) => m.id))
739
- * ```
740
- */
741
- public abstract listModels(): PluginApiReturn<PluginAIInspirationListModelsResult>
742
-
743
- /**
744
- * Get capability flags for a model.
745
- *
746
- * @param args - Object containing `modelId`.
747
- * @returns Capability flags such as reference, site-context, region, and keyframe support.
748
- *
749
- * @examplePrompt What can this model do?
750
- * @examplePrompt Does the default model support reference images?
751
- * @examplePrompt Check if the video model supports keyframes
752
- *
753
- * # Example
754
- * ```ts
755
- * const { defaultModelId } = await snaptrude.presentation.aiInspiration.listModels()
756
- * const { capability } = await snaptrude.presentation.aiInspiration.getModelCapabilities({
757
- * modelId: defaultModelId,
758
- * })
759
- * console.log(capability.supportsReferenceImages, capability.maxExtraImages)
760
- * ```
761
- */
762
- public abstract getModelCapabilities(
763
- args: PluginAIInspirationGetModelCapabilitiesArgs,
764
- ): PluginApiReturn<PluginAIInspirationGetModelCapabilitiesResult>
765
-
766
- /**
767
- * List image/view/video sources on the current Present page.
768
- *
769
- * @param args - Optional filters. Set `includeGenerated` to include AI outputs.
770
- * @returns Serializable shape references using Present canvas shape IDs.
771
- *
772
- * @examplePrompt List the images I can generate from on this page
773
- * @examplePrompt What source shapes are on the present canvas?
774
- * @examplePrompt Show me the reference images available for AI generation
775
- *
776
- * # Example
777
- * ```ts
778
- * const { sources } = await snaptrude.presentation.aiInspiration.listSources({ includeGenerated: true })
779
- * for (const s of sources) console.log(s.kind, s.shapeId, s.name)
780
- * ```
781
- */
782
- public abstract listSources(
783
- args: PluginAIInspirationListSourcesArgs,
784
- ): PluginApiReturn<PluginAIInspirationListSourcesResult>
785
-
786
- /**
787
- * Get selected Present canvas shapes that AI Inspiration can use.
788
- *
789
- * @returns Selected shape IDs and resolved source references.
790
- *
791
- * @examplePrompt Generate from what I have selected
792
- * @examplePrompt Which of my selected shapes can be used as AI sources?
793
- *
794
- * # Example
795
- * ```ts
796
- * const { selectedShapeIds, sources } = await snaptrude.presentation.aiInspiration.getSelection()
797
- * console.log(selectedShapeIds.length, "selected,", sources.length, "usable")
798
- * ```
799
- */
800
- public abstract getSelection(): PluginApiReturn<PluginAIInspirationGetSelectionResult>
801
-
802
- /**
803
- * Get the curated AI Inspiration preset catalog.
804
- *
805
- * @returns Preset categories and presets.
806
- *
807
- * @examplePrompt What style presets are available?
808
- * @examplePrompt List the curated AI generation presets
809
- * @examplePrompt Show me the exterior render styles
810
- *
811
- * # Example
812
- * ```ts
813
- * const { categories, presets } = await snaptrude.presentation.aiInspiration.getPresetCatalog()
814
- * const exterior = presets.filter((p) => p.categoryLabel === "Exterior")
815
- * console.log(categories.map((c) => c.label), exterior.map((p) => p.name))
816
- * ```
817
- */
818
- public abstract getPresetCatalog(): PluginApiReturn<PluginAIInspirationGetPresetCatalogResult>
819
-
820
- /**
821
- * Generate an image or video from a Present canvas source.
822
- *
823
- * @param args - Generation options including source, prompt, model, references, site context,
824
- * region guidance, sketch guidance, video options, and run mode.
825
- * @returns The created canvas output(s) in blocking mode, or a `jobId` when
826
- * called with `runMode: "job"`.
827
- *
828
- * @examplePrompt Generate an image from this sketch
829
- * @examplePrompt Render the selected view as a photorealistic image
830
- * @examplePrompt Make an AI image of a modern facade from this source
831
- * @examplePrompt Generate a video from this image
832
- * @examplePrompt Turn this massing into a rendered street view
833
- *
834
- * # Example
835
- * ```ts
836
- * const { sources } = await snaptrude.presentation.aiInspiration.listSources({})
837
- * const [source, ...refs] = sources
838
- * const { outputs } = await snaptrude.presentation.aiInspiration.generate({
839
- * sourceShapeId: source.shapeId,
840
- * prompt: "Photorealistic render of a modern timber facade at dusk",
841
- * referenceShapeIds: refs.slice(0, 2).map((r) => r.shapeId),
842
- * referenceStrength: "medium",
843
- * })
844
- * for (const out of outputs ?? []) console.log(out.outputType, out.shapeId, out.outputUrl)
845
- * ```
846
- */
847
- public abstract generate(
848
- args: PluginAIInspirationGenerateArgs,
849
- ): PluginApiReturn<PluginAIInspirationRunResult>
850
-
851
- /**
852
- * Refine/upscale an AI Inspiration source image.
853
- *
854
- * @param args - Source shape, optional upscale factor, and run mode.
855
- * @returns The refined canvas output(s) in blocking mode, or a `jobId` when
856
- * called with `runMode: "job"`.
857
- *
858
- * @examplePrompt Upscale this AI image
859
- * @examplePrompt Refine and sharpen the selected render
860
- * @examplePrompt Make this generated image higher resolution
861
- *
862
- * # Example
863
- * ```ts
864
- * const { sources } = await snaptrude.presentation.aiInspiration.listSources({ includeGenerated: true })
865
- * const image = sources.find((s) => s.kind === "image")
866
- * if (image) {
867
- * const { outputs } = await snaptrude.presentation.aiInspiration.refine({
868
- * sourceShapeId: image.shapeId,
869
- * upscaleFactor: 2,
870
- * })
871
- * console.log(outputs?.[0]?.shapeId)
872
- * }
873
- * ```
874
- */
875
- public abstract refine(
876
- args: PluginAIInspirationRefineArgs,
877
- ): PluginApiReturn<PluginAIInspirationRunResult>
878
-
879
- /**
880
- * Get a transient AI Inspiration job by ID.
881
- *
882
- * @param args - Object containing `jobId`.
883
- * @returns The job with status, progress, and result when completed.
884
- *
885
- * @examplePrompt Is my render finished?
886
- * @examplePrompt Check on the generation job
887
- *
888
- * # Example
889
- * ```ts
890
- * const { jobId } = await snaptrude.presentation.aiInspiration.generate({
891
- * sourceShapeId: source.shapeId,
892
- * prompt: "Aerial dusk render",
893
- * runMode: "job",
894
- * })
895
- * const { job } = await snaptrude.presentation.aiInspiration.getJob({ jobId })
896
- * console.log(job.status, job.progress?.message)
897
- * ```
898
- */
899
- public abstract getJob(
900
- args: PluginAIInspirationJobArgs,
901
- ): PluginApiReturn<PluginAIInspirationGetJobResult>
902
-
903
- /**
904
- * Cancel a transient AI Inspiration job.
905
- *
906
- * @param args - Object containing `jobId`.
907
- * @returns The job after the cancel request.
908
- *
909
- * @examplePrompt Cancel the running generation
910
- * @examplePrompt Stop that AI job
911
- *
912
- * # Example
913
- * ```ts
914
- * const { job } = await snaptrude.presentation.aiInspiration.cancelJob({ jobId })
915
- * console.log(job.status) // "cancelled" (or a terminal state it already reached)
916
- * ```
917
- */
918
- public abstract cancelJob(
919
- args: PluginAIInspirationJobArgs,
920
- ): PluginApiReturn<PluginAIInspirationCancelJobResult>
921
-
922
- /**
923
- * List transient AI Inspiration jobs created in the current host session.
924
- *
925
- * @returns Jobs with their statuses, newest first.
926
- *
927
- * @examplePrompt What AI jobs are running?
928
- * @examplePrompt Show my generation queue
929
- *
930
- * # Example
931
- * ```ts
932
- * const { jobs } = await snaptrude.presentation.aiInspiration.listJobs()
933
- * const running = jobs.filter((j) => j.status === "running" || j.status === "queued")
934
- * console.log(running.map((j) => `${j.jobId}: ${j.method}`))
935
- * ```
936
- */
937
- public abstract listJobs(): PluginApiReturn<PluginAIInspirationListJobsResult>
938
-
939
- /**
940
- * Get the sanitized workflow graph containing a Present shape.
941
- *
942
- * @param args - Object containing `shapeId`.
943
- * @returns The workflow and matching node, or `null` values when the shape is not in a workflow.
944
- *
945
- * @examplePrompt Show the generation history of this image
946
- * @examplePrompt What workflow produced this shape?
947
- *
948
- * # Example
949
- * ```ts
950
- * const { workflow, node } = await snaptrude.presentation.aiInspiration.getWorkflowForShape({
951
- * shapeId: selected.shapeId,
952
- * })
953
- * if (workflow && node) console.log(node.id, workflow.edgeIds.length, "edges")
954
- * ```
955
- */
956
- public abstract getWorkflowForShape(
957
- args: PluginAIInspirationGetWorkflowForShapeArgs,
958
- ): PluginApiReturn<PluginAIInspirationGetWorkflowForShapeResult>
959
-
960
- /**
961
- * Build a rerun plan for the selected workflow branch ending at a shape.
962
- *
963
- * @param args - Object containing `shapeId`.
964
- * @returns Ready plan data or an unavailable reason.
965
- *
966
- * @examplePrompt Can I rerun the steps that produced this output?
967
- * @examplePrompt Preview the rerun for this generated image
968
- *
969
- * # Example
970
- * ```ts
971
- * const plan = await snaptrude.presentation.aiInspiration.getSelectedBranchRerunPlan({
972
- * shapeId: selected.shapeId,
973
- * })
974
- * if (plan.status === "ready") console.log(plan.edges.map((e) => e.operation.label))
975
- * else console.log("Cannot rerun:", plan.reason)
976
- * ```
977
- */
978
- public abstract getSelectedBranchRerunPlan(
979
- args: PluginAIInspirationGetWorkflowForShapeArgs,
980
- ): PluginApiReturn<PluginAIInspirationRerunPlanResult>
981
-
982
- /**
983
- * Rerun the selected workflow branch and supersede the previous branch.
984
- *
985
- * @param args - Selected shape, optional end frame shape, and run mode.
986
- * @returns New canvas outputs in blocking mode, or a `jobId` when called with
987
- * `runMode: "job"`.
988
- *
989
- * @examplePrompt Rerun this generation branch
990
- * @examplePrompt Regenerate this output with the same steps
991
- *
992
- * # Example
993
- * ```ts
994
- * const { outputs } = await snaptrude.presentation.aiInspiration.rerunSelectedBranch({
995
- * shapeId: selected.shapeId,
996
- * })
997
- * console.log(outputs?.map((o) => o.shapeId))
998
- * ```
999
- */
1000
- public abstract rerunSelectedBranch(
1001
- args: PluginAIInspirationRerunSelectedBranchArgs,
1002
- ): PluginApiReturn<PluginAIInspirationRunResult>
1003
-
1004
- /**
1005
- * Extract a reusable recipe draft from the workflow path ending at a shape.
1006
- *
1007
- * @param args - Object containing `shapeId`.
1008
- * @returns A recipe draft or an unavailable reason.
1009
- *
1010
- * @examplePrompt Turn this workflow into a reusable recipe
1011
- * @examplePrompt Save the generation steps behind this image
1012
- *
1013
- * # Example
1014
- * ```ts
1015
- * const extraction = await snaptrude.presentation.aiInspiration.extractRecipeFromShape({
1016
- * shapeId: selected.shapeId,
1017
- * })
1018
- * if (extraction.status === "ready") console.log(extraction.draft.summary)
1019
- * ```
1020
- */
1021
- public abstract extractRecipeFromShape(
1022
- args: PluginAIInspirationExtractRecipeFromShapeArgs,
1023
- ): PluginApiReturn<PluginAIInspirationExtractionResult>
1024
-
1025
- /**
1026
- * List project-level AI Inspiration recipes stored in Present document metadata.
1027
- *
1028
- * @returns Saved project recipes.
1029
- *
1030
- * @examplePrompt What AI recipes are saved in this project?
1031
- * @examplePrompt List my generation recipes
1032
- *
1033
- * # Example
1034
- * ```ts
1035
- * const { recipes } = await snaptrude.presentation.aiInspiration.listRecipes()
1036
- * console.log(recipes.map((r) => `${r.name} → ${r.outputKind}`))
1037
- * ```
1038
- */
1039
- public abstract listRecipes(): PluginApiReturn<PluginAIInspirationListRecipesResult>
1040
-
1041
- /**
1042
- * Save a project-level AI Inspiration recipe.
1043
- *
1044
- * @param args - Recipe draft and desired name.
1045
- * @returns Saved, duplicate, invalid-name, or failed status.
1046
- *
1047
- * @examplePrompt Save this recipe as "Dusk facade render"
1048
- * @examplePrompt Store these generation steps for reuse
1049
- *
1050
- * # Example
1051
- * ```ts
1052
- * const extraction = await snaptrude.presentation.aiInspiration.extractRecipeFromShape({
1053
- * shapeId: selected.shapeId,
1054
- * })
1055
- * if (extraction.status === "ready") {
1056
- * const saved = await snaptrude.presentation.aiInspiration.saveRecipe({
1057
- * draft: extraction.draft,
1058
- * name: "Dusk facade render",
1059
- * })
1060
- * console.log(saved.status, saved.recipe?.id)
1061
- * }
1062
- * ```
1063
- */
1064
- public abstract saveRecipe(
1065
- args: PluginAIInspirationSaveRecipeArgs,
1066
- ): PluginApiReturn<PluginAIInspirationSaveRecipeResult>
1067
-
1068
- /**
1069
- * Delete a project-level AI Inspiration recipe.
1070
- *
1071
- * @param args - Object containing `recipeId`.
1072
- * @returns Whether a recipe was deleted.
1073
- *
1074
- * @examplePrompt Delete the facade render recipe
1075
- * @examplePrompt Remove that saved AI recipe
1076
- *
1077
- * # Example
1078
- * ```ts
1079
- * const { recipes } = await snaptrude.presentation.aiInspiration.listRecipes()
1080
- * const stale = recipes.find((r) => r.name === "Old style test")
1081
- * if (stale) {
1082
- * const { deleted } = await snaptrude.presentation.aiInspiration.deleteRecipe({ recipeId: stale.id })
1083
- * console.log(deleted)
1084
- * }
1085
- * ```
1086
- */
1087
- public abstract deleteRecipe(
1088
- args: PluginAIInspirationDeleteRecipeArgs,
1089
- ): PluginApiReturn<PluginAIInspirationDeleteRecipeResult>
1090
-
1091
- /**
1092
- * Run a saved or inline recipe against Present canvas slot shapes.
1093
- *
1094
- * @param args - Saved `recipeId` or inline `recipe`, slot shape IDs, and run mode.
1095
- * @returns Canvas outputs in blocking mode, or a `jobId` when called with
1096
- * `runMode: "job"`.
1097
- *
1098
- * @examplePrompt Apply my saved recipe to this image
1099
- * @examplePrompt Run the dusk-render recipe on the selected view
1100
- *
1101
- * # Example
1102
- * ```ts
1103
- * const { recipes } = await snaptrude.presentation.aiInspiration.listRecipes()
1104
- * const recipe = recipes[0]
1105
- * const { sources } = await snaptrude.presentation.aiInspiration.listSources({})
1106
- * const { outputs } = await snaptrude.presentation.aiInspiration.runRecipe({
1107
- * recipeId: recipe.id,
1108
- * slotShapeIds: { [recipe.slots[0].id]: sources[0].shapeId },
1109
- * })
1110
- * console.log(outputs?.map((o) => o.outputUrl))
1111
- * ```
1112
- */
1113
- public abstract runRecipe(
1114
- args: PluginAIInspirationRunRecipeArgs,
1115
- ): PluginApiReturn<PluginAIInspirationRunResult>
1116
- }
1
+ import * as z from "zod"
2
+ import type { PluginApiReturn } from "../../types"
3
+
4
+ const JsonPrimitive = z.union([z.string(), z.number(), z.boolean(), z.null()])
5
+ type JsonValue =
6
+ | z.infer<typeof JsonPrimitive>
7
+ | JsonValue[]
8
+ | { [key: string]: JsonValue }
9
+ const JsonValue: z.ZodType<JsonValue> = z.lazy(() =>
10
+ z.union([JsonPrimitive, z.array(JsonValue), z.record(z.string(), JsonValue)]),
11
+ )
12
+
13
+ export const PluginAIInspirationRunMode = z.enum(["blocking", "job"])
14
+ export type PluginAIInspirationRunMode = z.infer<
15
+ typeof PluginAIInspirationRunMode
16
+ >
17
+
18
+ export const PluginAIInspirationOutputKind = z.enum([
19
+ "source",
20
+ "image",
21
+ "video",
22
+ ])
23
+ export type PluginAIInspirationOutputKind = z.infer<
24
+ typeof PluginAIInspirationOutputKind
25
+ >
26
+
27
+ export const PluginAIInspirationModelOutput = z.enum(["image", "video"])
28
+ export type PluginAIInspirationModelOutput = z.infer<
29
+ typeof PluginAIInspirationModelOutput
30
+ >
31
+
32
+ export const PluginAIInspirationRuntimeProvider = z.enum(["gpt", "fal"])
33
+ export type PluginAIInspirationRuntimeProvider = z.infer<
34
+ typeof PluginAIInspirationRuntimeProvider
35
+ >
36
+
37
+ export const PluginAIInspirationPromptStrategy = z.enum([
38
+ "gpt-image",
39
+ "fal-image",
40
+ "fal-video",
41
+ ])
42
+ export type PluginAIInspirationPromptStrategy = z.infer<
43
+ typeof PluginAIInspirationPromptStrategy
44
+ >
45
+
46
+ export const PluginAIInspirationShapeKind = z.enum(["image", "view", "video"])
47
+ export type PluginAIInspirationShapeKind = z.infer<
48
+ typeof PluginAIInspirationShapeKind
49
+ >
50
+
51
+ export const PluginAIInspirationVideoMode = z.enum([
52
+ "animate",
53
+ "references",
54
+ "keyframes",
55
+ ])
56
+ export type PluginAIInspirationVideoMode = z.infer<
57
+ typeof PluginAIInspirationVideoMode
58
+ >
59
+
60
+ export const PluginAIInspirationVideoMotion = z.enum([
61
+ "auto",
62
+ "slow-dolly",
63
+ "subtle-orbit",
64
+ "reveal",
65
+ ])
66
+ export type PluginAIInspirationVideoMotion = z.infer<
67
+ typeof PluginAIInspirationVideoMotion
68
+ >
69
+
70
+ export const PluginAIInspirationVideoDuration = z.enum(["4s", "6s", "8s"])
71
+ export type PluginAIInspirationVideoDuration = z.infer<
72
+ typeof PluginAIInspirationVideoDuration
73
+ >
74
+
75
+ export const PluginAIInspirationJobStatus = z.enum([
76
+ "queued",
77
+ "running",
78
+ "completed",
79
+ "failed",
80
+ "cancelled",
81
+ ])
82
+ export type PluginAIInspirationJobStatus = z.infer<
83
+ typeof PluginAIInspirationJobStatus
84
+ >
85
+
86
+ export const PluginAIInspirationWorkflowRunState = z.enum([
87
+ "current",
88
+ "stale",
89
+ "running",
90
+ "failed",
91
+ "superseded",
92
+ ])
93
+ export type PluginAIInspirationWorkflowRunState = z.infer<
94
+ typeof PluginAIInspirationWorkflowRunState
95
+ >
96
+
97
+ export const PluginAIInspirationRegionHint = z.object({
98
+ x: z.number().finite(),
99
+ y: z.number().finite(),
100
+ w: z.number().finite().positive(),
101
+ h: z.number().finite().positive(),
102
+ })
103
+ export type PluginAIInspirationRegionHint = z.infer<
104
+ typeof PluginAIInspirationRegionHint
105
+ >
106
+
107
+ export const PluginAIInspirationPoint = z.object({
108
+ x: z.number().finite(),
109
+ y: z.number().finite(),
110
+ })
111
+ export type PluginAIInspirationPoint = z.infer<typeof PluginAIInspirationPoint>
112
+
113
+ export const PluginAIInspirationTextAnnotation = z.object({
114
+ text: z.string().min(1),
115
+ x: z.number().finite().optional(),
116
+ y: z.number().finite().optional(),
117
+ })
118
+ export type PluginAIInspirationTextAnnotation = z.infer<
119
+ typeof PluginAIInspirationTextAnnotation
120
+ >
121
+
122
+ export const PluginAIInspirationSketchGuidance = z.object({
123
+ visualShapeIds: z.array(z.string()).optional(),
124
+ textAnnotations: z.array(PluginAIInspirationTextAnnotation).optional(),
125
+ })
126
+ export type PluginAIInspirationSketchGuidance = z.infer<
127
+ typeof PluginAIInspirationSketchGuidance
128
+ >
129
+
130
+ export const PluginAIInspirationSiteOptions = z.object({
131
+ includeSatellite: z.boolean().optional(),
132
+ includeStreetView: z.boolean().optional(),
133
+ includeAerial: z.boolean().optional(),
134
+ aerialBearing: z.number().finite().optional(),
135
+ aerialPitch: z.number().finite().optional(),
136
+ selectedDiagramIds: z.array(z.string()).optional(),
137
+ location: z
138
+ .object({
139
+ lat: z.number().finite(),
140
+ lng: z.number().finite(),
141
+ })
142
+ .optional(),
143
+ })
144
+ export type PluginAIInspirationSiteOptions = z.infer<
145
+ typeof PluginAIInspirationSiteOptions
146
+ >
147
+
148
+ export const PluginAIInspirationAppliedPreset = z.object({
149
+ source: z.enum(["curated", "user"]),
150
+ presetId: z.string().min(1),
151
+ name: z.string().min(1),
152
+ savedPresetKind: z.enum(["prompt", "style"]).optional(),
153
+ stylePrompt: z.string().optional(),
154
+ modelId: z.string().optional(),
155
+ referenceImages: z
156
+ .array(
157
+ z.object({
158
+ url: z.string().min(1),
159
+ label: z.string().optional(),
160
+ weight: z.number().finite().optional(),
161
+ }),
162
+ )
163
+ .optional(),
164
+ siteDefaults: z
165
+ .object({
166
+ includeSatellite: z.boolean().optional(),
167
+ includeStreetView: z.boolean().optional(),
168
+ includeAerial: z.boolean().optional(),
169
+ })
170
+ .optional(),
171
+ })
172
+ export type PluginAIInspirationAppliedPreset = z.infer<
173
+ typeof PluginAIInspirationAppliedPreset
174
+ >
175
+
176
+ export const PluginAIInspirationVideoOptions = z.object({
177
+ mode: PluginAIInspirationVideoMode.optional(),
178
+ endFrameShapeId: z.string().optional(),
179
+ motion: PluginAIInspirationVideoMotion.optional(),
180
+ duration: PluginAIInspirationVideoDuration.optional(),
181
+ })
182
+ export type PluginAIInspirationVideoOptions = z.infer<
183
+ typeof PluginAIInspirationVideoOptions
184
+ >
185
+
186
+ export const PluginAIInspirationModel = z.object({
187
+ id: z.string(),
188
+ label: z.string(),
189
+ supportsMultiImage: z.boolean(),
190
+ output: PluginAIInspirationModelOutput,
191
+ isDefault: z.boolean().optional(),
192
+ })
193
+ export type PluginAIInspirationModel = z.infer<typeof PluginAIInspirationModel>
194
+
195
+ export const PluginAIInspirationModelCapability = z.object({
196
+ id: z.string(),
197
+ output: PluginAIInspirationModelOutput,
198
+ provider: PluginAIInspirationRuntimeProvider,
199
+ supportsRegionEdit: z.boolean(),
200
+ supportsReferenceImages: z.boolean(),
201
+ supportsStylePresets: z.boolean(),
202
+ supportsSiteContext: z.boolean(),
203
+ supportsSketchGuidance: z.boolean(),
204
+ supportsKeyframes: z.boolean(),
205
+ maxExtraImages: z.number().int().nonnegative(),
206
+ promptStrategy: PluginAIInspirationPromptStrategy,
207
+ })
208
+ export type PluginAIInspirationModelCapability = z.infer<
209
+ typeof PluginAIInspirationModelCapability
210
+ >
211
+
212
+ export const PluginAIInspirationListModelsResult = z.object({
213
+ defaultModelId: z.string(),
214
+ models: z.array(PluginAIInspirationModel),
215
+ })
216
+ export type PluginAIInspirationListModelsResult = z.infer<
217
+ typeof PluginAIInspirationListModelsResult
218
+ >
219
+
220
+ export const PluginAIInspirationGetModelCapabilitiesArgs = z.object({
221
+ modelId: z.string().min(1),
222
+ })
223
+ export type PluginAIInspirationGetModelCapabilitiesArgs = z.infer<
224
+ typeof PluginAIInspirationGetModelCapabilitiesArgs
225
+ >
226
+
227
+ export const PluginAIInspirationGetModelCapabilitiesResult = z.object({
228
+ capability: PluginAIInspirationModelCapability,
229
+ })
230
+ export type PluginAIInspirationGetModelCapabilitiesResult = z.infer<
231
+ typeof PluginAIInspirationGetModelCapabilitiesResult
232
+ >
233
+
234
+ export const PluginAIInspirationShapeRef = z.object({
235
+ shapeId: z.string(),
236
+ assetId: z.string().optional(),
237
+ kind: PluginAIInspirationShapeKind,
238
+ name: z.string().optional(),
239
+ width: z.number().finite().optional(),
240
+ height: z.number().finite().optional(),
241
+ outputType: PluginAIInspirationOutputKind.optional(),
242
+ sourceUrl: z.string().optional(),
243
+ })
244
+ export type PluginAIInspirationShapeRef = z.infer<
245
+ typeof PluginAIInspirationShapeRef
246
+ >
247
+
248
+ export const PluginAIInspirationListSourcesArgs = z.object({
249
+ includeGenerated: z.boolean().optional(),
250
+ includeSourceUrl: z.boolean().optional(),
251
+ })
252
+ export type PluginAIInspirationListSourcesArgs = z.infer<
253
+ typeof PluginAIInspirationListSourcesArgs
254
+ >
255
+
256
+ export const PluginAIInspirationListSourcesResult = z.object({
257
+ sources: z.array(PluginAIInspirationShapeRef),
258
+ })
259
+ export type PluginAIInspirationListSourcesResult = z.infer<
260
+ typeof PluginAIInspirationListSourcesResult
261
+ >
262
+
263
+ export const PluginAIInspirationGetSelectionResult = z.object({
264
+ selectedShapeIds: z.array(z.string()),
265
+ sources: z.array(PluginAIInspirationShapeRef),
266
+ })
267
+ export type PluginAIInspirationGetSelectionResult = z.infer<
268
+ typeof PluginAIInspirationGetSelectionResult
269
+ >
270
+
271
+ export const PluginAIInspirationPresetReferenceImage = z.object({
272
+ url: z.string(),
273
+ label: z.string().optional(),
274
+ weight: z.number().finite().optional(),
275
+ })
276
+ export type PluginAIInspirationPresetReferenceImage = z.infer<
277
+ typeof PluginAIInspirationPresetReferenceImage
278
+ >
279
+
280
+ export const PluginAIInspirationPreset = z.object({
281
+ id: z.string(),
282
+ name: z.string(),
283
+ source: z.enum(["curated", "user"]),
284
+ modelId: z.string(),
285
+ categoryId: z.string().optional(),
286
+ categoryLabel: z.string().optional(),
287
+ description: z.string().optional(),
288
+ previewImageUrl: z.string().optional(),
289
+ prompt: z.string().optional(),
290
+ stylePrompt: z.string().optional(),
291
+ tags: z.array(z.string()).optional(),
292
+ referenceImages: z.array(PluginAIInspirationPresetReferenceImage).optional(),
293
+ siteDefaults: PluginAIInspirationAppliedPreset.shape.siteDefaults.optional(),
294
+ })
295
+ export type PluginAIInspirationPreset = z.infer<
296
+ typeof PluginAIInspirationPreset
297
+ >
298
+
299
+ export const PluginAIInspirationPresetCategory = z.object({
300
+ id: z.string(),
301
+ label: z.string(),
302
+ description: z.string().optional(),
303
+ })
304
+ export type PluginAIInspirationPresetCategory = z.infer<
305
+ typeof PluginAIInspirationPresetCategory
306
+ >
307
+
308
+ export const PluginAIInspirationGetPresetCatalogResult = z.object({
309
+ categories: z.array(PluginAIInspirationPresetCategory),
310
+ presets: z.array(PluginAIInspirationPreset),
311
+ })
312
+ export type PluginAIInspirationGetPresetCatalogResult = z.infer<
313
+ typeof PluginAIInspirationGetPresetCatalogResult
314
+ >
315
+
316
+ export const PluginAIInspirationOutput = z.object({
317
+ outputType: z.enum(["image", "video"]),
318
+ shapeId: z.string(),
319
+ assetId: z.string(),
320
+ outputUrl: z.string().optional(),
321
+ position: PluginAIInspirationPoint.optional(),
322
+ })
323
+ export type PluginAIInspirationOutput = z.infer<
324
+ typeof PluginAIInspirationOutput
325
+ >
326
+
327
+ export const PluginAIInspirationDebugSummary = z.record(z.string(), JsonValue)
328
+ export type PluginAIInspirationDebugSummary = z.infer<
329
+ typeof PluginAIInspirationDebugSummary
330
+ >
331
+
332
+ export const PluginAIInspirationRunMetadata = z.object({
333
+ geometryFidelity: z.string().optional(),
334
+ debugSummary: PluginAIInspirationDebugSummary.optional(),
335
+ streetViewComposite: z
336
+ .object({
337
+ used: z.boolean(),
338
+ renderMode: z.enum(["prompt_refs_default", "masked_composite_pilot"]),
339
+ backgroundLabel: z.string().optional(),
340
+ })
341
+ .optional(),
342
+ })
343
+ export type PluginAIInspirationRunMetadata = z.infer<
344
+ typeof PluginAIInspirationRunMetadata
345
+ >
346
+
347
+ export const PluginAIInspirationGenerateArgs = z.object({
348
+ sourceShapeId: z.string().min(1),
349
+ prompt: z.string().min(1).max(8000),
350
+ modelId: z.string().optional(),
351
+ referenceShapeIds: z.array(z.string()).max(12).optional(),
352
+ referenceStrength: z.enum(["low", "medium", "high"]).optional(),
353
+ appliedPreset: PluginAIInspirationAppliedPreset.optional(),
354
+ site: PluginAIInspirationSiteOptions.optional(),
355
+ regionHint: PluginAIInspirationRegionHint.optional(),
356
+ sketchGuidance: PluginAIInspirationSketchGuidance.optional(),
357
+ video: PluginAIInspirationVideoOptions.optional(),
358
+ runMode: PluginAIInspirationRunMode.optional(),
359
+ })
360
+ export type PluginAIInspirationGenerateArgs = z.infer<
361
+ typeof PluginAIInspirationGenerateArgs
362
+ >
363
+
364
+ export const PluginAIInspirationRunResult = z.object({
365
+ jobId: z.string().optional(),
366
+ output: PluginAIInspirationOutput.optional(),
367
+ outputs: z.array(PluginAIInspirationOutput).optional(),
368
+ metadata: PluginAIInspirationRunMetadata.optional(),
369
+ })
370
+ export type PluginAIInspirationRunResult = z.infer<
371
+ typeof PluginAIInspirationRunResult
372
+ >
373
+
374
+ export const PluginAIInspirationRefineArgs = z.object({
375
+ sourceShapeId: z.string().min(1),
376
+ upscaleFactor: z
377
+ .union([z.literal(1.5), z.literal(2), z.literal(4)])
378
+ .optional(),
379
+ runMode: PluginAIInspirationRunMode.optional(),
380
+ })
381
+ export type PluginAIInspirationRefineArgs = z.infer<
382
+ typeof PluginAIInspirationRefineArgs
383
+ >
384
+
385
+ export const PluginAIInspirationJobProgress = z.object({
386
+ currentStep: z.number().int().nonnegative().optional(),
387
+ totalSteps: z.number().int().nonnegative().optional(),
388
+ message: z.string().optional(),
389
+ })
390
+ export type PluginAIInspirationJobProgress = z.infer<
391
+ typeof PluginAIInspirationJobProgress
392
+ >
393
+
394
+ export const PluginAIInspirationJob = z.object({
395
+ jobId: z.string(),
396
+ status: PluginAIInspirationJobStatus,
397
+ createdAt: z.number(),
398
+ updatedAt: z.number(),
399
+ completedAt: z.number().optional(),
400
+ method: z.string(),
401
+ progress: PluginAIInspirationJobProgress.optional(),
402
+ result: PluginAIInspirationRunResult.optional(),
403
+ error: z.string().optional(),
404
+ })
405
+ export type PluginAIInspirationJob = z.infer<typeof PluginAIInspirationJob>
406
+
407
+ export const PluginAIInspirationJobArgs = z.object({
408
+ jobId: z.string().min(1),
409
+ })
410
+ export type PluginAIInspirationJobArgs = z.infer<
411
+ typeof PluginAIInspirationJobArgs
412
+ >
413
+
414
+ export const PluginAIInspirationGetJobResult = z.object({
415
+ job: PluginAIInspirationJob,
416
+ })
417
+ export type PluginAIInspirationGetJobResult = z.infer<
418
+ typeof PluginAIInspirationGetJobResult
419
+ >
420
+
421
+ export const PluginAIInspirationCancelJobResult = z.object({
422
+ job: PluginAIInspirationJob,
423
+ })
424
+ export type PluginAIInspirationCancelJobResult = z.infer<
425
+ typeof PluginAIInspirationCancelJobResult
426
+ >
427
+
428
+ export const PluginAIInspirationListJobsResult = z.object({
429
+ jobs: z.array(PluginAIInspirationJob),
430
+ })
431
+ export type PluginAIInspirationListJobsResult = z.infer<
432
+ typeof PluginAIInspirationListJobsResult
433
+ >
434
+
435
+ export const PluginAIInspirationWorkflowVideoConfig = z.object({
436
+ mode: z.string().optional(),
437
+ motion: z.string().optional(),
438
+ duration: z.string().optional(),
439
+ endFrameShapeId: z.string().optional(),
440
+ })
441
+ export type PluginAIInspirationWorkflowVideoConfig = z.infer<
442
+ typeof PluginAIInspirationWorkflowVideoConfig
443
+ >
444
+
445
+ export const PluginAIInspirationGenerationInputSnapshot = z.object({
446
+ version: z.literal(1),
447
+ meta: z.record(z.string(), JsonValue),
448
+ regionHint: PluginAIInspirationRegionHint.optional(),
449
+ sketchGuidance: z.record(z.string(), JsonValue).optional(),
450
+ sourceCameraHeading: z.number().finite().optional(),
451
+ })
452
+ export type PluginAIInspirationGenerationInputSnapshot = z.infer<
453
+ typeof PluginAIInspirationGenerationInputSnapshot
454
+ >
455
+
456
+ export const PluginAIInspirationWorkflowOperation = z.object({
457
+ type: z.enum(["generate-image", "refine", "generate-video"]),
458
+ label: z.string(),
459
+ prompt: z.string().optional(),
460
+ modelId: z.string().optional(),
461
+ presetId: z.string().optional(),
462
+ presetName: z.string().optional(),
463
+ refineFactor: z.number().finite().optional(),
464
+ sourceRole: z.enum(["primary", "end-frame"]).optional(),
465
+ video: PluginAIInspirationWorkflowVideoConfig.optional(),
466
+ generationInput: PluginAIInspirationGenerationInputSnapshot.optional(),
467
+ })
468
+ export type PluginAIInspirationWorkflowOperation = z.infer<
469
+ typeof PluginAIInspirationWorkflowOperation
470
+ >
471
+
472
+ export const PluginAIInspirationWorkflowNode = z.object({
473
+ id: z.string(),
474
+ shapeId: z.string(),
475
+ assetId: z.string().optional(),
476
+ kind: PluginAIInspirationOutputKind,
477
+ state: z.string(),
478
+ runState: PluginAIInspirationWorkflowRunState.optional(),
479
+ staleReason: z.string().optional(),
480
+ incomingEdgeIds: z.array(z.string()),
481
+ outgoingEdgeIds: z.array(z.string()),
482
+ createdAt: z.number(),
483
+ updatedAt: z.number(),
484
+ })
485
+ export type PluginAIInspirationWorkflowNode = z.infer<
486
+ typeof PluginAIInspirationWorkflowNode
487
+ >
488
+
489
+ export const PluginAIInspirationWorkflowEdge = z.object({
490
+ id: z.string(),
491
+ sourceNodeId: z.string(),
492
+ targetNodeId: z.string(),
493
+ arrowShapeId: z.string().optional(),
494
+ operation: PluginAIInspirationWorkflowOperation,
495
+ state: z.string(),
496
+ runState: PluginAIInspirationWorkflowRunState.optional(),
497
+ staleReason: z.string().optional(),
498
+ supersededByEdgeId: z.string().optional(),
499
+ createdAt: z.number(),
500
+ updatedAt: z.number(),
501
+ })
502
+ export type PluginAIInspirationWorkflowEdge = z.infer<
503
+ typeof PluginAIInspirationWorkflowEdge
504
+ >
505
+
506
+ export const PluginAIInspirationWorkflow = z.object({
507
+ id: z.string(),
508
+ rootNodeIds: z.array(z.string()),
509
+ nodeIds: z.array(z.string()),
510
+ edgeIds: z.array(z.string()),
511
+ nodes: z.record(z.string(), PluginAIInspirationWorkflowNode),
512
+ edges: z.record(z.string(), PluginAIInspirationWorkflowEdge),
513
+ createdAt: z.number(),
514
+ updatedAt: z.number(),
515
+ })
516
+ export type PluginAIInspirationWorkflow = z.infer<
517
+ typeof PluginAIInspirationWorkflow
518
+ >
519
+
520
+ export const PluginAIInspirationGetWorkflowForShapeArgs = z.object({
521
+ shapeId: z.string().min(1),
522
+ })
523
+ export type PluginAIInspirationGetWorkflowForShapeArgs = z.infer<
524
+ typeof PluginAIInspirationGetWorkflowForShapeArgs
525
+ >
526
+
527
+ export const PluginAIInspirationGetWorkflowForShapeResult = z.object({
528
+ workflow: PluginAIInspirationWorkflow.nullable(),
529
+ node: PluginAIInspirationWorkflowNode.nullable(),
530
+ })
531
+ export type PluginAIInspirationGetWorkflowForShapeResult = z.infer<
532
+ typeof PluginAIInspirationGetWorkflowForShapeResult
533
+ >
534
+
535
+ export const PluginAIInspirationRerunPlanResult = z.discriminatedUnion(
536
+ "status",
537
+ [
538
+ z.object({
539
+ status: z.literal("ready"),
540
+ workflowId: z.string(),
541
+ sourceNode: PluginAIInspirationWorkflowNode,
542
+ edgeIds: z.array(z.string()),
543
+ edges: z.array(PluginAIInspirationWorkflowEdge),
544
+ recipe: z.lazy(() => PluginAIInspirationRecipe),
545
+ needsEndFrame: z.boolean(),
546
+ defaultEndFrameShapeId: z.string().nullable(),
547
+ }),
548
+ z.object({
549
+ status: z.literal("unavailable"),
550
+ reason: z.enum([
551
+ "not-in-workflow",
552
+ "source-only",
553
+ "running",
554
+ "missing-input",
555
+ ]),
556
+ }),
557
+ ],
558
+ )
559
+ export type PluginAIInspirationRerunPlanResult = z.infer<
560
+ typeof PluginAIInspirationRerunPlanResult
561
+ >
562
+
563
+ export const PluginAIInspirationRerunSelectedBranchArgs = z.object({
564
+ shapeId: z.string().min(1),
565
+ endFrameShapeId: z.string().optional(),
566
+ runMode: PluginAIInspirationRunMode.optional(),
567
+ })
568
+ export type PluginAIInspirationRerunSelectedBranchArgs = z.infer<
569
+ typeof PluginAIInspirationRerunSelectedBranchArgs
570
+ >
571
+
572
+ export const PluginAIInspirationRecipeSlot = z.object({
573
+ id: z.string(),
574
+ type: z.enum(["source-image", "end-frame"]),
575
+ label: z.string(),
576
+ required: z.boolean(),
577
+ })
578
+ export type PluginAIInspirationRecipeSlot = z.infer<
579
+ typeof PluginAIInspirationRecipeSlot
580
+ >
581
+
582
+ export const PluginAIInspirationRecipeStep = z.object({
583
+ id: z.string(),
584
+ operation: PluginAIInspirationWorkflowOperation,
585
+ outputKind: z.enum(["image", "video"]),
586
+ })
587
+ export type PluginAIInspirationRecipeStep = z.infer<
588
+ typeof PluginAIInspirationRecipeStep
589
+ >
590
+
591
+ export const PluginAIInspirationRecipeDraft = z.object({
592
+ name: z.string(),
593
+ summary: z.string(),
594
+ slots: z.array(PluginAIInspirationRecipeSlot),
595
+ steps: z.array(PluginAIInspirationRecipeStep).min(1).max(20),
596
+ outputKind: z.enum(["image", "video"]),
597
+ thumbnailUrl: z.string().optional(),
598
+ })
599
+ export type PluginAIInspirationRecipeDraft = z.infer<
600
+ typeof PluginAIInspirationRecipeDraft
601
+ >
602
+
603
+ export const PluginAIInspirationRecipe: z.ZodType<
604
+ PluginAIInspirationRecipeDraft & {
605
+ version: 1
606
+ id: string
607
+ fingerprint?: string
608
+ createdAt: number
609
+ updatedAt: number
610
+ }
611
+ > = PluginAIInspirationRecipeDraft.extend({
612
+ version: z.literal(1),
613
+ id: z.string(),
614
+ fingerprint: z.string().optional(),
615
+ createdAt: z.number(),
616
+ updatedAt: z.number(),
617
+ })
618
+ export type PluginAIInspirationRecipe = z.infer<
619
+ typeof PluginAIInspirationRecipe
620
+ >
621
+
622
+ export const PluginAIInspirationExtractionResult = z.discriminatedUnion(
623
+ "status",
624
+ [
625
+ z.object({
626
+ status: z.literal("ready"),
627
+ draft: PluginAIInspirationRecipeDraft,
628
+ }),
629
+ z.object({
630
+ status: z.literal("unavailable"),
631
+ reason: z.enum([
632
+ "not-in-workflow",
633
+ "source-only",
634
+ "missing-workflow",
635
+ "missing-node",
636
+ "missing-input",
637
+ "invalid-workflow",
638
+ ]),
639
+ }),
640
+ ],
641
+ )
642
+ export type PluginAIInspirationExtractionResult = z.infer<
643
+ typeof PluginAIInspirationExtractionResult
644
+ >
645
+
646
+ export const PluginAIInspirationListRecipesResult = z.object({
647
+ recipes: z.array(PluginAIInspirationRecipe),
648
+ })
649
+ export type PluginAIInspirationListRecipesResult = z.infer<
650
+ typeof PluginAIInspirationListRecipesResult
651
+ >
652
+
653
+ export const PluginAIInspirationSaveRecipeArgs = z.object({
654
+ draft: PluginAIInspirationRecipeDraft,
655
+ name: z.string().min(1),
656
+ })
657
+ export type PluginAIInspirationSaveRecipeArgs = z.infer<
658
+ typeof PluginAIInspirationSaveRecipeArgs
659
+ >
660
+
661
+ export const PluginAIInspirationSaveRecipeResult = z.discriminatedUnion(
662
+ "status",
663
+ [
664
+ z.object({ status: z.literal("saved"), recipe: PluginAIInspirationRecipe }),
665
+ z.object({
666
+ status: z.literal("duplicate"),
667
+ recipe: PluginAIInspirationRecipe,
668
+ }),
669
+ z.object({ status: z.literal("invalid-name"), recipe: z.null() }),
670
+ z.object({ status: z.literal("failed"), recipe: z.null() }),
671
+ ],
672
+ )
673
+ export type PluginAIInspirationSaveRecipeResult = z.infer<
674
+ typeof PluginAIInspirationSaveRecipeResult
675
+ >
676
+
677
+ export const PluginAIInspirationDeleteRecipeArgs = z.object({
678
+ recipeId: z.string().min(1),
679
+ })
680
+ export type PluginAIInspirationDeleteRecipeArgs = z.infer<
681
+ typeof PluginAIInspirationDeleteRecipeArgs
682
+ >
683
+
684
+ export const PluginAIInspirationDeleteRecipeResult = z.object({
685
+ deleted: z.boolean(),
686
+ })
687
+ export type PluginAIInspirationDeleteRecipeResult = z.infer<
688
+ typeof PluginAIInspirationDeleteRecipeResult
689
+ >
690
+
691
+ export const PluginAIInspirationExtractRecipeFromShapeArgs = z.object({
692
+ shapeId: z.string().min(1),
693
+ })
694
+ export type PluginAIInspirationExtractRecipeFromShapeArgs = z.infer<
695
+ typeof PluginAIInspirationExtractRecipeFromShapeArgs
696
+ >
697
+
698
+ export const PluginAIInspirationRunRecipeArgs = z.object({
699
+ recipeId: z.string().optional(),
700
+ recipe: PluginAIInspirationRecipe.optional(),
701
+ slotShapeIds: z.record(z.string(), z.string()),
702
+ runMode: PluginAIInspirationRunMode.optional(),
703
+ })
704
+ export type PluginAIInspirationRunRecipeArgs = z.infer<
705
+ typeof PluginAIInspirationRunRecipeArgs
706
+ >
707
+
708
+ /**
709
+ * Present-mode AI Inspiration APIs.
710
+ *
711
+ * These APIs operate on Present canvas shape IDs and inherit the current user's
712
+ * AI quota. They create outputs on the Present canvas; pure backend generation
713
+ * without canvas output is intentionally out of scope.
714
+ *
715
+ * Long-running generations can be started with `runMode: "job"` and tracked via
716
+ * {@linkcode PluginPresentationAIInspirationApi.getJob} /
717
+ * {@linkcode PluginPresentationAIInspirationApi.listJobs}; the default
718
+ * `"blocking"` mode resolves with the canvas outputs directly.
719
+ *
720
+ * Accessed via `snaptrude.presentation.aiInspiration`.
721
+ */
722
+ export abstract class PluginPresentationAIInspirationApi {
723
+ constructor() {}
724
+
725
+ /**
726
+ * List AI Inspiration models that can be used for generation.
727
+ *
728
+ * @returns The default model ID and available model descriptors.
729
+ *
730
+ * @examplePrompt What AI inspiration models can I use?
731
+ * @examplePrompt List the available image and video models
732
+ * @examplePrompt Which generation model is the default?
733
+ *
734
+ * # Example
735
+ * ```ts
736
+ * const { defaultModelId, models } = await snaptrude.presentation.aiInspiration.listModels()
737
+ * const videoModels = models.filter((m) => m.output === "video")
738
+ * console.log(defaultModelId, videoModels.map((m) => m.id))
739
+ * ```
740
+ */
741
+ public abstract listModels(): PluginApiReturn<PluginAIInspirationListModelsResult>
742
+
743
+ /**
744
+ * Get capability flags for a model.
745
+ *
746
+ * @param args - Object containing `modelId`.
747
+ * @returns Capability flags such as reference, site-context, region, and keyframe support.
748
+ *
749
+ * @examplePrompt What can this model do?
750
+ * @examplePrompt Does the default model support reference images?
751
+ * @examplePrompt Check if the video model supports keyframes
752
+ *
753
+ * # Example
754
+ * ```ts
755
+ * const { defaultModelId } = await snaptrude.presentation.aiInspiration.listModels()
756
+ * const { capability } = await snaptrude.presentation.aiInspiration.getModelCapabilities({
757
+ * modelId: defaultModelId,
758
+ * })
759
+ * console.log(capability.supportsReferenceImages, capability.maxExtraImages)
760
+ * ```
761
+ */
762
+ public abstract getModelCapabilities(
763
+ args: PluginAIInspirationGetModelCapabilitiesArgs,
764
+ ): PluginApiReturn<PluginAIInspirationGetModelCapabilitiesResult>
765
+
766
+ /**
767
+ * List image/view/video sources on the current Present page.
768
+ *
769
+ * @param args - Optional filters. Set `includeGenerated` to include AI outputs.
770
+ * @returns Serializable shape references using Present canvas shape IDs.
771
+ *
772
+ * @examplePrompt List the images I can generate from on this page
773
+ * @examplePrompt What source shapes are on the present canvas?
774
+ * @examplePrompt Show me the reference images available for AI generation
775
+ *
776
+ * # Example
777
+ * ```ts
778
+ * const { sources } = await snaptrude.presentation.aiInspiration.listSources({ includeGenerated: true })
779
+ * for (const s of sources) console.log(s.kind, s.shapeId, s.name)
780
+ * ```
781
+ */
782
+ public abstract listSources(
783
+ args: PluginAIInspirationListSourcesArgs,
784
+ ): PluginApiReturn<PluginAIInspirationListSourcesResult>
785
+
786
+ /**
787
+ * Get selected Present canvas shapes that AI Inspiration can use.
788
+ *
789
+ * @returns Selected shape IDs and resolved source references.
790
+ *
791
+ * @examplePrompt Generate from what I have selected
792
+ * @examplePrompt Which of my selected shapes can be used as AI sources?
793
+ *
794
+ * # Example
795
+ * ```ts
796
+ * const { selectedShapeIds, sources } = await snaptrude.presentation.aiInspiration.getSelection()
797
+ * console.log(selectedShapeIds.length, "selected,", sources.length, "usable")
798
+ * ```
799
+ */
800
+ public abstract getSelection(): PluginApiReturn<PluginAIInspirationGetSelectionResult>
801
+
802
+ /**
803
+ * Get the curated AI Inspiration preset catalog.
804
+ *
805
+ * @returns Preset categories and presets.
806
+ *
807
+ * @examplePrompt What style presets are available?
808
+ * @examplePrompt List the curated AI generation presets
809
+ * @examplePrompt Show me the exterior render styles
810
+ *
811
+ * # Example
812
+ * ```ts
813
+ * const { categories, presets } = await snaptrude.presentation.aiInspiration.getPresetCatalog()
814
+ * const exterior = presets.filter((p) => p.categoryLabel === "Exterior")
815
+ * console.log(categories.map((c) => c.label), exterior.map((p) => p.name))
816
+ * ```
817
+ */
818
+ public abstract getPresetCatalog(): PluginApiReturn<PluginAIInspirationGetPresetCatalogResult>
819
+
820
+ /**
821
+ * Generate an image or video from a Present canvas source.
822
+ *
823
+ * @param args - Generation options including source, prompt, model, references, site context,
824
+ * region guidance, sketch guidance, video options, and run mode.
825
+ * @returns The created canvas output(s) in blocking mode, or a `jobId` when
826
+ * called with `runMode: "job"`.
827
+ *
828
+ * @examplePrompt Generate an image from this sketch
829
+ * @examplePrompt Render the selected view as a photorealistic image
830
+ * @examplePrompt Make an AI image of a modern facade from this source
831
+ * @examplePrompt Generate a video from this image
832
+ * @examplePrompt Turn this massing into a rendered street view
833
+ *
834
+ * # Example
835
+ * ```ts
836
+ * const { sources } = await snaptrude.presentation.aiInspiration.listSources({})
837
+ * const [source, ...refs] = sources
838
+ * const { outputs } = await snaptrude.presentation.aiInspiration.generate({
839
+ * sourceShapeId: source.shapeId,
840
+ * prompt: "Photorealistic render of a modern timber facade at dusk",
841
+ * referenceShapeIds: refs.slice(0, 2).map((r) => r.shapeId),
842
+ * referenceStrength: "medium",
843
+ * })
844
+ * for (const out of outputs ?? []) console.log(out.outputType, out.shapeId, out.outputUrl)
845
+ * ```
846
+ */
847
+ public abstract generate(
848
+ args: PluginAIInspirationGenerateArgs,
849
+ ): PluginApiReturn<PluginAIInspirationRunResult>
850
+
851
+ /**
852
+ * Refine/upscale an AI Inspiration source image.
853
+ *
854
+ * @param args - Source shape, optional upscale factor, and run mode.
855
+ * @returns The refined canvas output(s) in blocking mode, or a `jobId` when
856
+ * called with `runMode: "job"`.
857
+ *
858
+ * @examplePrompt Upscale this AI image
859
+ * @examplePrompt Refine and sharpen the selected render
860
+ * @examplePrompt Make this generated image higher resolution
861
+ *
862
+ * # Example
863
+ * ```ts
864
+ * const { sources } = await snaptrude.presentation.aiInspiration.listSources({ includeGenerated: true })
865
+ * const image = sources.find((s) => s.kind === "image")
866
+ * if (image) {
867
+ * const { outputs } = await snaptrude.presentation.aiInspiration.refine({
868
+ * sourceShapeId: image.shapeId,
869
+ * upscaleFactor: 2,
870
+ * })
871
+ * console.log(outputs?.[0]?.shapeId)
872
+ * }
873
+ * ```
874
+ */
875
+ public abstract refine(
876
+ args: PluginAIInspirationRefineArgs,
877
+ ): PluginApiReturn<PluginAIInspirationRunResult>
878
+
879
+ /**
880
+ * Get a transient AI Inspiration job by ID.
881
+ *
882
+ * @param args - Object containing `jobId`.
883
+ * @returns The job with status, progress, and result when completed.
884
+ *
885
+ * @examplePrompt Is my render finished?
886
+ * @examplePrompt Check on the generation job
887
+ *
888
+ * # Example
889
+ * ```ts
890
+ * const { jobId } = await snaptrude.presentation.aiInspiration.generate({
891
+ * sourceShapeId: source.shapeId,
892
+ * prompt: "Aerial dusk render",
893
+ * runMode: "job",
894
+ * })
895
+ * const { job } = await snaptrude.presentation.aiInspiration.getJob({ jobId })
896
+ * console.log(job.status, job.progress?.message)
897
+ * ```
898
+ */
899
+ public abstract getJob(
900
+ args: PluginAIInspirationJobArgs,
901
+ ): PluginApiReturn<PluginAIInspirationGetJobResult>
902
+
903
+ /**
904
+ * Cancel a transient AI Inspiration job.
905
+ *
906
+ * @param args - Object containing `jobId`.
907
+ * @returns The job after the cancel request.
908
+ *
909
+ * @examplePrompt Cancel the running generation
910
+ * @examplePrompt Stop that AI job
911
+ *
912
+ * # Example
913
+ * ```ts
914
+ * const { job } = await snaptrude.presentation.aiInspiration.cancelJob({ jobId })
915
+ * console.log(job.status) // "cancelled" (or a terminal state it already reached)
916
+ * ```
917
+ */
918
+ public abstract cancelJob(
919
+ args: PluginAIInspirationJobArgs,
920
+ ): PluginApiReturn<PluginAIInspirationCancelJobResult>
921
+
922
+ /**
923
+ * List transient AI Inspiration jobs created in the current host session.
924
+ *
925
+ * @returns Jobs with their statuses, newest first.
926
+ *
927
+ * @examplePrompt What AI jobs are running?
928
+ * @examplePrompt Show my generation queue
929
+ *
930
+ * # Example
931
+ * ```ts
932
+ * const { jobs } = await snaptrude.presentation.aiInspiration.listJobs()
933
+ * const running = jobs.filter((j) => j.status === "running" || j.status === "queued")
934
+ * console.log(running.map((j) => `${j.jobId}: ${j.method}`))
935
+ * ```
936
+ */
937
+ public abstract listJobs(): PluginApiReturn<PluginAIInspirationListJobsResult>
938
+
939
+ /**
940
+ * Get the sanitized workflow graph containing a Present shape.
941
+ *
942
+ * @param args - Object containing `shapeId`.
943
+ * @returns The workflow and matching node, or `null` values when the shape is not in a workflow.
944
+ *
945
+ * @examplePrompt Show the generation history of this image
946
+ * @examplePrompt What workflow produced this shape?
947
+ *
948
+ * # Example
949
+ * ```ts
950
+ * const { workflow, node } = await snaptrude.presentation.aiInspiration.getWorkflowForShape({
951
+ * shapeId: selected.shapeId,
952
+ * })
953
+ * if (workflow && node) console.log(node.id, workflow.edgeIds.length, "edges")
954
+ * ```
955
+ */
956
+ public abstract getWorkflowForShape(
957
+ args: PluginAIInspirationGetWorkflowForShapeArgs,
958
+ ): PluginApiReturn<PluginAIInspirationGetWorkflowForShapeResult>
959
+
960
+ /**
961
+ * Build a rerun plan for the selected workflow branch ending at a shape.
962
+ *
963
+ * @param args - Object containing `shapeId`.
964
+ * @returns Ready plan data or an unavailable reason.
965
+ *
966
+ * @examplePrompt Can I rerun the steps that produced this output?
967
+ * @examplePrompt Preview the rerun for this generated image
968
+ *
969
+ * # Example
970
+ * ```ts
971
+ * const plan = await snaptrude.presentation.aiInspiration.getSelectedBranchRerunPlan({
972
+ * shapeId: selected.shapeId,
973
+ * })
974
+ * if (plan.status === "ready") console.log(plan.edges.map((e) => e.operation.label))
975
+ * else console.log("Cannot rerun:", plan.reason)
976
+ * ```
977
+ */
978
+ public abstract getSelectedBranchRerunPlan(
979
+ args: PluginAIInspirationGetWorkflowForShapeArgs,
980
+ ): PluginApiReturn<PluginAIInspirationRerunPlanResult>
981
+
982
+ /**
983
+ * Rerun the selected workflow branch and supersede the previous branch.
984
+ *
985
+ * @param args - Selected shape, optional end frame shape, and run mode.
986
+ * @returns New canvas outputs in blocking mode, or a `jobId` when called with
987
+ * `runMode: "job"`.
988
+ *
989
+ * @examplePrompt Rerun this generation branch
990
+ * @examplePrompt Regenerate this output with the same steps
991
+ *
992
+ * # Example
993
+ * ```ts
994
+ * const { outputs } = await snaptrude.presentation.aiInspiration.rerunSelectedBranch({
995
+ * shapeId: selected.shapeId,
996
+ * })
997
+ * console.log(outputs?.map((o) => o.shapeId))
998
+ * ```
999
+ */
1000
+ public abstract rerunSelectedBranch(
1001
+ args: PluginAIInspirationRerunSelectedBranchArgs,
1002
+ ): PluginApiReturn<PluginAIInspirationRunResult>
1003
+
1004
+ /**
1005
+ * Extract a reusable recipe draft from the workflow path ending at a shape.
1006
+ *
1007
+ * @param args - Object containing `shapeId`.
1008
+ * @returns A recipe draft or an unavailable reason.
1009
+ *
1010
+ * @examplePrompt Turn this workflow into a reusable recipe
1011
+ * @examplePrompt Save the generation steps behind this image
1012
+ *
1013
+ * # Example
1014
+ * ```ts
1015
+ * const extraction = await snaptrude.presentation.aiInspiration.extractRecipeFromShape({
1016
+ * shapeId: selected.shapeId,
1017
+ * })
1018
+ * if (extraction.status === "ready") console.log(extraction.draft.summary)
1019
+ * ```
1020
+ */
1021
+ public abstract extractRecipeFromShape(
1022
+ args: PluginAIInspirationExtractRecipeFromShapeArgs,
1023
+ ): PluginApiReturn<PluginAIInspirationExtractionResult>
1024
+
1025
+ /**
1026
+ * List project-level AI Inspiration recipes stored in Present document metadata.
1027
+ *
1028
+ * @returns Saved project recipes.
1029
+ *
1030
+ * @examplePrompt What AI recipes are saved in this project?
1031
+ * @examplePrompt List my generation recipes
1032
+ *
1033
+ * # Example
1034
+ * ```ts
1035
+ * const { recipes } = await snaptrude.presentation.aiInspiration.listRecipes()
1036
+ * console.log(recipes.map((r) => `${r.name} → ${r.outputKind}`))
1037
+ * ```
1038
+ */
1039
+ public abstract listRecipes(): PluginApiReturn<PluginAIInspirationListRecipesResult>
1040
+
1041
+ /**
1042
+ * Save a project-level AI Inspiration recipe.
1043
+ *
1044
+ * @param args - Recipe draft and desired name.
1045
+ * @returns Saved, duplicate, invalid-name, or failed status.
1046
+ *
1047
+ * @examplePrompt Save this recipe as "Dusk facade render"
1048
+ * @examplePrompt Store these generation steps for reuse
1049
+ *
1050
+ * # Example
1051
+ * ```ts
1052
+ * const extraction = await snaptrude.presentation.aiInspiration.extractRecipeFromShape({
1053
+ * shapeId: selected.shapeId,
1054
+ * })
1055
+ * if (extraction.status === "ready") {
1056
+ * const saved = await snaptrude.presentation.aiInspiration.saveRecipe({
1057
+ * draft: extraction.draft,
1058
+ * name: "Dusk facade render",
1059
+ * })
1060
+ * console.log(saved.status, saved.recipe?.id)
1061
+ * }
1062
+ * ```
1063
+ */
1064
+ public abstract saveRecipe(
1065
+ args: PluginAIInspirationSaveRecipeArgs,
1066
+ ): PluginApiReturn<PluginAIInspirationSaveRecipeResult>
1067
+
1068
+ /**
1069
+ * Delete a project-level AI Inspiration recipe.
1070
+ *
1071
+ * @param args - Object containing `recipeId`.
1072
+ * @returns Whether a recipe was deleted.
1073
+ *
1074
+ * @examplePrompt Delete the facade render recipe
1075
+ * @examplePrompt Remove that saved AI recipe
1076
+ *
1077
+ * # Example
1078
+ * ```ts
1079
+ * const { recipes } = await snaptrude.presentation.aiInspiration.listRecipes()
1080
+ * const stale = recipes.find((r) => r.name === "Old style test")
1081
+ * if (stale) {
1082
+ * const { deleted } = await snaptrude.presentation.aiInspiration.deleteRecipe({ recipeId: stale.id })
1083
+ * console.log(deleted)
1084
+ * }
1085
+ * ```
1086
+ */
1087
+ public abstract deleteRecipe(
1088
+ args: PluginAIInspirationDeleteRecipeArgs,
1089
+ ): PluginApiReturn<PluginAIInspirationDeleteRecipeResult>
1090
+
1091
+ /**
1092
+ * Run a saved or inline recipe against Present canvas slot shapes.
1093
+ *
1094
+ * @param args - Saved `recipeId` or inline `recipe`, slot shape IDs, and run mode.
1095
+ * @returns Canvas outputs in blocking mode, or a `jobId` when called with
1096
+ * `runMode: "job"`.
1097
+ *
1098
+ * @examplePrompt Apply my saved recipe to this image
1099
+ * @examplePrompt Run the dusk-render recipe on the selected view
1100
+ *
1101
+ * # Example
1102
+ * ```ts
1103
+ * const { recipes } = await snaptrude.presentation.aiInspiration.listRecipes()
1104
+ * const recipe = recipes[0]
1105
+ * const { sources } = await snaptrude.presentation.aiInspiration.listSources({})
1106
+ * const { outputs } = await snaptrude.presentation.aiInspiration.runRecipe({
1107
+ * recipeId: recipe.id,
1108
+ * slotShapeIds: { [recipe.slots[0].id]: sources[0].shapeId },
1109
+ * })
1110
+ * console.log(outputs?.map((o) => o.outputUrl))
1111
+ * ```
1112
+ */
1113
+ public abstract runRecipe(
1114
+ args: PluginAIInspirationRunRecipeArgs,
1115
+ ): PluginApiReturn<PluginAIInspirationRunResult>
1116
+ }