@gentbajko/slopify 3.25.9 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (718) hide show
  1. package/dist/adapters/account-limits.js +30 -0
  2. package/dist/adapters/alignment/audio.js +1 -1
  3. package/dist/adapters/alignment/cache.js +4 -6
  4. package/dist/adapters/alignment/ctc.js +1 -2
  5. package/dist/adapters/alignment/lock.js +4 -3
  6. package/dist/adapters/alignment/multilingual.js +2 -4
  7. package/dist/adapters/alignment/prefetch.js +2 -1
  8. package/dist/adapters/alignment/runner.js +1 -1
  9. package/dist/adapters/alignment/worker.js +3 -2
  10. package/dist/adapters/explain.js +10 -12
  11. package/dist/adapters/ffmpeg.js +19 -1
  12. package/dist/adapters/host-cli/index.js +21 -4
  13. package/dist/adapters/host-cli/transport.js +2 -1
  14. package/dist/adapters/http-failure.js +53 -0
  15. package/dist/adapters/image/bytes.js +2 -1
  16. package/dist/adapters/image/codex.js +42 -9
  17. package/dist/adapters/image/fal.js +21 -53
  18. package/dist/adapters/image/google.js +33 -56
  19. package/dist/adapters/image/models.js +2 -2
  20. package/dist/adapters/image/openai.js +22 -48
  21. package/dist/adapters/image/reference.js +36 -0
  22. package/dist/adapters/image/replicate.js +21 -49
  23. package/dist/adapters/image/video.js +2 -1
  24. package/dist/adapters/interest/search-interest.js +113 -0
  25. package/dist/adapters/key-probes.js +54 -3
  26. package/dist/adapters/llm/antigravity-models.js +1 -1
  27. package/dist/adapters/llm/antigravity.js +11 -6
  28. package/dist/adapters/llm/assistant-cli.js +388 -0
  29. package/dist/adapters/llm/child-session.js +83 -0
  30. package/dist/adapters/llm/claude-code-models.js +52 -99
  31. package/dist/adapters/llm/claude-code.js +16 -4
  32. package/dist/adapters/llm/codex-limits.js +27 -68
  33. package/dist/adapters/llm/codex-models.js +1 -1
  34. package/dist/adapters/llm/codex-server-models.js +61 -109
  35. package/dist/adapters/llm/codex.js +12 -1
  36. package/dist/adapters/llm/document-workspace.js +3 -2
  37. package/dist/adapters/llm/image-workspace.js +3 -2
  38. package/dist/adapters/llm/openrouter.js +12 -48
  39. package/dist/adapters/llm/run-cli.js +9 -24
  40. package/dist/adapters/llm/sse-lines.js +5 -1
  41. package/dist/adapters/model-access.js +37 -0
  42. package/dist/adapters/tts/cartesia.js +15 -46
  43. package/dist/adapters/tts/elevenlabs.js +20 -52
  44. package/dist/adapters/tts/gemini.js +21 -41
  45. package/dist/adapters/tts/inworld-async.js +6 -2
  46. package/dist/adapters/tts/inworld.js +6 -2
  47. package/dist/adapters/tts/openai.js +20 -50
  48. package/dist/adapters/tts/system.js +2 -1
  49. package/dist/assets/models-lifecycle.yaml +6 -0
  50. package/dist/assistant-wiring.js +60 -0
  51. package/dist/autopilot-timers.js +59 -0
  52. package/dist/catalog/lifecycle.js +52 -0
  53. package/dist/catalog/propose.js +204 -0
  54. package/dist/catalog/registry.js +23 -14
  55. package/dist/catalog/schema.js +4 -1
  56. package/dist/catalog/store.js +39 -0
  57. package/dist/catalog/validate.js +5 -2
  58. package/dist/edge/autostart/native.js +3 -5
  59. package/dist/edge/autostart/prompt.js +2 -1
  60. package/dist/edge/autostart/service.js +3 -4
  61. package/dist/edge/cli-args.js +3 -4
  62. package/dist/edge/cli.js +2 -1
  63. package/dist/edge/docker-install/apply.js +11 -11
  64. package/dist/edge/docker-install/run.js +2 -1
  65. package/dist/edge/docker-install/state.js +4 -3
  66. package/dist/edge/docker-install/tree.js +2 -4
  67. package/dist/edge/docker-install/volume.js +3 -2
  68. package/dist/edge/docker.js +5 -4
  69. package/dist/edge/events/hub.js +5 -5
  70. package/dist/edge/http/actions.js +11 -32
  71. package/dist/edge/http/actor.js +5 -3
  72. package/dist/edge/http/app.js +86 -11
  73. package/dist/edge/http/assistant.js +129 -0
  74. package/dist/edge/http/audio-preview.js +4 -11
  75. package/dist/edge/http/auditions.js +1 -1
  76. package/dist/edge/http/autostart.js +5 -5
  77. package/dist/edge/http/backups.js +2 -4
  78. package/dist/edge/http/channel-memory.js +9 -22
  79. package/dist/edge/http/channels.js +14 -27
  80. package/dist/edge/http/checkpoints.js +39 -21
  81. package/dist/edge/http/design-templates.js +167 -0
  82. package/dist/edge/http/designs.js +178 -0
  83. package/dist/edge/http/diagnostics.js +5 -1
  84. package/dist/edge/http/document-themes.js +5 -14
  85. package/dist/edge/http/draft-files.js +1 -3
  86. package/dist/edge/http/draft-problem.js +5 -10
  87. package/dist/edge/http/drafts.js +3 -3
  88. package/dist/edge/http/entries.js +6 -9
  89. package/dist/edge/http/extension-auth.js +27 -0
  90. package/dist/edge/http/external-reviews.js +12 -11
  91. package/dist/edge/http/files.js +5 -11
  92. package/dist/edge/http/folder-location.js +1 -4
  93. package/dist/edge/http/fonts.js +0 -7
  94. package/dist/edge/http/home.js +47 -14
  95. package/dist/edge/http/host-cli.js +18 -8
  96. package/dist/edge/http/ids.js +8 -0
  97. package/dist/edge/http/keywords.js +35 -0
  98. package/dist/edge/http/model-checks.js +132 -0
  99. package/dist/edge/http/narration-peaks.js +5 -13
  100. package/dist/edge/http/onboarding.js +30 -26
  101. package/dist/edge/http/open-folder.js +5 -10
  102. package/dist/edge/http/outputs.js +7 -14
  103. package/dist/edge/http/patch-notes.js +6 -12
  104. package/dist/edge/http/planning.js +3 -7
  105. package/dist/edge/http/problem.js +2 -4
  106. package/dist/edge/http/project-create.js +2 -1
  107. package/dist/edge/http/project-templates.js +31 -19
  108. package/dist/edge/http/projects.js +24 -16
  109. package/dist/edge/http/prompts.js +9 -16
  110. package/dist/edge/http/pronunciations.js +1 -2
  111. package/dist/edge/http/providers.js +48 -34
  112. package/dist/edge/http/refusal.js +29 -0
  113. package/dist/edge/http/remote-access.js +40 -0
  114. package/dist/edge/http/remote-guard.js +71 -0
  115. package/dist/edge/http/request-guard.js +91 -0
  116. package/dist/edge/http/reviews.js +12 -25
  117. package/dist/edge/http/revision-files.js +6 -11
  118. package/dist/edge/http/revisions.js +14 -19
  119. package/dist/edge/http/run-cost.js +1 -2
  120. package/dist/edge/http/same-page.js +80 -0
  121. package/dist/edge/http/schedules.js +69 -40
  122. package/dist/edge/http/settings.js +27 -14
  123. package/dist/edge/http/social.js +283 -0
  124. package/dist/edge/http/staging.js +3 -5
  125. package/dist/edge/http/storage-files.js +5 -7
  126. package/dist/edge/http/storage.js +33 -25
  127. package/dist/edge/http/studio.js +94 -69
  128. package/dist/edge/http/style-preview.js +3 -6
  129. package/dist/edge/http/subtitles.js +3 -17
  130. package/dist/edge/http/template-studio.js +436 -0
  131. package/dist/edge/http/trash.js +11 -12
  132. package/dist/edge/http/tutorial.js +1 -2
  133. package/dist/edge/http/tutorials.js +5 -11
  134. package/dist/edge/http/update.js +7 -13
  135. package/dist/edge/http/waveform.js +3 -6
  136. package/dist/edge/http/youtube-edits.js +3 -4
  137. package/dist/edge/mcp/assistant.js +279 -0
  138. package/dist/edge/mcp/attribution.js +8 -2
  139. package/dist/edge/mcp/call-route.js +11 -2
  140. package/dist/edge/mcp/excluded-routes.js +29 -3
  141. package/dist/edge/mcp/http.js +11 -2
  142. package/dist/edge/mcp/instructions.js +6 -4
  143. package/dist/edge/mcp/library-tools.js +9 -5
  144. package/dist/edge/mcp/remake-tools.js +7 -4
  145. package/dist/edge/mcp/route-tool.js +35 -15
  146. package/dist/edge/mcp/server.js +13 -8
  147. package/dist/edge/mcp/tools-channels.js +11 -9
  148. package/dist/edge/mcp/tools-designs.js +165 -0
  149. package/dist/edge/mcp/tools-library.js +19 -7
  150. package/dist/edge/mcp/tools-planning.js +40 -21
  151. package/dist/edge/mcp/tools-projects.js +38 -11
  152. package/dist/edge/mcp/tools-publishing.js +9 -9
  153. package/dist/edge/mcp/tools-runs.js +23 -10
  154. package/dist/edge/mcp/tools-schedules.js +32 -8
  155. package/dist/edge/mcp/tools-setup.js +75 -11
  156. package/dist/edge/mcp/tools-social.js +47 -0
  157. package/dist/edge/mcp/tools-storage.js +11 -3
  158. package/dist/edge/mcp/tools-template-studio.js +166 -0
  159. package/dist/edge/mcp/tools.js +6 -0
  160. package/dist/edge/remote-access/cli.js +71 -0
  161. package/dist/edge/remote-access/model.js +32 -0
  162. package/dist/edge/remote-access/rules.js +207 -0
  163. package/dist/edge/remote-access/service.js +203 -0
  164. package/dist/edge/remote-access/store.js +44 -0
  165. package/dist/edge/remote-access/views.js +43 -0
  166. package/dist/extension/slopify-studio-chrome.zip +0 -0
  167. package/dist/extension/slopify-studio-firefox.zip +0 -0
  168. package/dist/host-cli/install.js +2 -2
  169. package/dist/host-cli/open-folder.js +2 -2
  170. package/dist/host-cli/paths.js +2 -4
  171. package/dist/host-cli/server.js +4 -4
  172. package/dist/host-cli/service.js +3 -3
  173. package/dist/host-cli/status.js +7 -7
  174. package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
  175. package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
  176. package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
  177. package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
  178. package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
  179. package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
  180. package/dist/kernel/db/migrations/0070-designs.sql +53 -0
  181. package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
  182. package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
  183. package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
  184. package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
  185. package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
  186. package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
  187. package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
  188. package/dist/kernel/db/migrations/0078-uploaded-from-links.sql +7 -0
  189. package/dist/kernel/db/tx.js +2 -4
  190. package/dist/kernel/errors.js +27 -1
  191. package/dist/kernel/json-answer.js +15 -0
  192. package/dist/kernel/lock.js +4 -9
  193. package/dist/kernel/paths.js +8 -0
  194. package/dist/kernel/pipeline.js +12 -0
  195. package/dist/kernel/ports/assistant-cli.js +4 -0
  196. package/dist/kernel/ports/host-cli.js +3 -0
  197. package/dist/kernel/ports/interest.js +4 -0
  198. package/dist/kernel/ports/languages.js +0 -3
  199. package/dist/kernel/ports/model.js +2 -0
  200. package/dist/kernel/ports/settings-places.js +31 -0
  201. package/dist/kernel/ports/system-speech.js +31 -3
  202. package/dist/kernel/runner/attempt.js +14 -4
  203. package/dist/kernel/runner/audition.js +3 -1
  204. package/dist/kernel/runner/checkpoint-authority.js +2 -1
  205. package/dist/kernel/runner/index.js +8 -10
  206. package/dist/kernel/runner/model-access.js +40 -0
  207. package/dist/kernel/runner/model-check.js +153 -0
  208. package/dist/kernel/runner/providers.js +18 -12
  209. package/dist/kernel/runner/standalone.js +11 -7
  210. package/dist/main.js +338 -21
  211. package/dist/model-catalog.js +20 -0
  212. package/dist/model-checks.js +166 -0
  213. package/dist/patch-notes/4.0.0.md +51 -0
  214. package/dist/patch-notes/4.1.0.md +42 -0
  215. package/dist/patch-notes/index.json +12 -0
  216. package/dist/slices/admission/heads.js +2 -1
  217. package/dist/slices/admission/listing-facts.js +95 -0
  218. package/dist/slices/admission/repo.js +11 -7
  219. package/dist/slices/admission/rules.js +50 -15
  220. package/dist/slices/admission/schema.js +8 -0
  221. package/dist/slices/admission/stage-writes.js +0 -3
  222. package/dist/slices/admission/start.js +48 -31
  223. package/dist/slices/admission/state-words.js +34 -5
  224. package/dist/slices/admission/substitute.js +7 -4
  225. package/dist/slices/agents/attention-posts.js +31 -0
  226. package/dist/slices/agents/attention-templates.js +33 -0
  227. package/dist/slices/agents/attention.js +10 -1
  228. package/dist/slices/agents/connection.js +2 -6
  229. package/dist/slices/agents/model.js +6 -3
  230. package/dist/slices/agents/repo.js +15 -7
  231. package/dist/slices/article/continuation.js +0 -63
  232. package/dist/slices/article/plain.js +3 -2
  233. package/dist/slices/article/segments.js +2 -62
  234. package/dist/slices/assistant/access.js +1 -0
  235. package/dist/slices/assistant/asks.js +80 -0
  236. package/dist/slices/assistant/cost.js +54 -0
  237. package/dist/slices/assistant/gate.js +222 -0
  238. package/dist/slices/assistant/model.js +86 -0
  239. package/dist/slices/assistant/names.js +23 -0
  240. package/dist/slices/assistant/prompt.js +74 -0
  241. package/dist/slices/assistant/repo.js +74 -0
  242. package/dist/slices/assistant/tokens.js +18 -0
  243. package/dist/slices/assistant/turn.js +344 -0
  244. package/dist/slices/autopilot/buffer.js +76 -0
  245. package/dist/slices/autopilot/model.js +14 -0
  246. package/dist/slices/autopilot/notify.js +27 -0
  247. package/dist/slices/autopilot/repo.js +34 -0
  248. package/dist/slices/autopilot/signals.js +194 -0
  249. package/dist/slices/autopilot/warnings.js +85 -0
  250. package/dist/slices/autopilot/weekly.js +100 -0
  251. package/dist/slices/backups/files.js +2 -6
  252. package/dist/slices/backups/repo.js +3 -15
  253. package/dist/slices/backups/service.js +8 -7
  254. package/dist/slices/channels/cast-images.js +3 -2
  255. package/dist/slices/channels/model.js +0 -1
  256. package/dist/slices/channels/rebrand.js +0 -3
  257. package/dist/slices/channels/repo.js +4 -0
  258. package/dist/slices/channels/schema.js +7 -1
  259. package/dist/slices/channels/service.js +10 -0
  260. package/dist/slices/channels/videos.js +3 -15
  261. package/dist/slices/checkpoints/index.js +0 -1
  262. package/dist/slices/control/providers.js +2 -28
  263. package/dist/slices/designs/artwork.js +66 -0
  264. package/dist/slices/designs/budget.js +23 -0
  265. package/dist/slices/designs/calls.js +124 -0
  266. package/dist/slices/designs/check-context.js +38 -0
  267. package/dist/slices/designs/check-text.js +43 -0
  268. package/dist/slices/designs/fields.js +88 -0
  269. package/dist/slices/designs/frames.js +34 -0
  270. package/dist/slices/designs/gate.js +130 -0
  271. package/dist/slices/designs/layout.js +293 -0
  272. package/dist/slices/designs/model.js +35 -0
  273. package/dist/slices/designs/pdf-job.js +23 -0
  274. package/dist/slices/designs/pdf-pages.js +30 -0
  275. package/dist/slices/designs/pdf-runner.js +68 -0
  276. package/dist/slices/designs/pdf-worker.js +24 -0
  277. package/dist/slices/designs/picture-size.js +79 -0
  278. package/dist/slices/designs/pictures.js +55 -0
  279. package/dist/slices/designs/quote.js +24 -0
  280. package/dist/slices/designs/render-args.js +36 -0
  281. package/dist/slices/designs/render-input.js +59 -0
  282. package/dist/slices/designs/render.js +215 -0
  283. package/dist/slices/designs/repo.js +101 -0
  284. package/dist/slices/designs/requests.js +80 -0
  285. package/dist/slices/designs/runner.js +239 -0
  286. package/dist/slices/designs/sample-repo.js +91 -0
  287. package/dist/slices/designs/sample.js +223 -0
  288. package/dist/slices/designs/schema.js +87 -0
  289. package/dist/slices/designs/sections.js +44 -0
  290. package/dist/slices/designs/service.js +233 -0
  291. package/dist/slices/designs/steps-repo.js +102 -0
  292. package/dist/slices/designs/studio-kind.js +39 -0
  293. package/dist/slices/designs/template-checks.js +44 -0
  294. package/dist/slices/designs/template-make.js +118 -0
  295. package/dist/slices/designs/templates.js +218 -0
  296. package/dist/slices/document/fonts.js +2 -1
  297. package/dist/slices/document/model.js +7 -4
  298. package/dist/slices/document/render.js +2 -1
  299. package/dist/slices/document/theme-schema.js +1 -1
  300. package/dist/slices/document/theme.js +49 -3
  301. package/dist/slices/episodes/summarize.js +6 -2
  302. package/dist/slices/estimate/index.js +72 -28
  303. package/dist/slices/estimate/requests.js +4 -4
  304. package/dist/slices/fixes/rules.js +3 -1
  305. package/dist/slices/fonts/catalog.js +5 -3
  306. package/dist/slices/fonts/coverage.js +2 -1
  307. package/dist/slices/fonts/discovery.js +3 -2
  308. package/dist/slices/fonts/files.js +2 -6
  309. package/dist/slices/fonts/index.js +0 -1
  310. package/dist/slices/fonts/sfnt.js +45 -10
  311. package/dist/slices/images/appearance.js +8 -16
  312. package/dist/slices/images/scenes.js +102 -28
  313. package/dist/slices/keywords/digest.js +85 -0
  314. package/dist/slices/keywords/facts.js +92 -0
  315. package/dist/slices/keywords/fill.js +80 -0
  316. package/dist/slices/keywords/model.js +75 -0
  317. package/dist/slices/keywords/rules.js +187 -0
  318. package/dist/slices/keywords/schema.js +28 -0
  319. package/dist/slices/keywords/specs.js +260 -0
  320. package/dist/slices/keywords/values.js +74 -0
  321. package/dist/slices/library/lint.js +29 -12
  322. package/dist/slices/library/model.js +2 -0
  323. package/dist/slices/library/photorealistic.js +4 -12
  324. package/dist/slices/library/rename.js +9 -7
  325. package/dist/slices/library/save.js +14 -10
  326. package/dist/slices/library/slots.js +37 -11
  327. package/dist/slices/library/transfer.js +5 -4
  328. package/dist/slices/library/used-by.js +25 -10
  329. package/dist/slices/loudness/loudnorm.js +53 -12
  330. package/dist/slices/loudness/model.js +3 -2
  331. package/dist/slices/loudness/sentence-level.js +2 -1
  332. package/dist/slices/model-checks/cost.js +61 -0
  333. package/dist/slices/model-checks/listing.js +124 -0
  334. package/dist/slices/model-checks/model.js +20 -0
  335. package/dist/slices/model-checks/record.js +32 -0
  336. package/dist/slices/model-checks/repo.js +120 -0
  337. package/dist/slices/model-checks/rules.js +125 -0
  338. package/dist/slices/model-checks/run.js +143 -0
  339. package/dist/slices/model-checks/service.js +198 -0
  340. package/dist/slices/model-upkeep/model.js +1 -1
  341. package/dist/slices/model-upkeep/switch.js +72 -27
  342. package/dist/slices/model-upkeep/usage.js +39 -13
  343. package/dist/slices/narration/breaths.js +3 -1
  344. package/dist/slices/narration/clean-pieces.js +3 -1
  345. package/dist/slices/narration/concat.js +2 -1
  346. package/dist/slices/narration/pauses-model.js +3 -2
  347. package/dist/slices/narration/peaks.js +3 -4
  348. package/dist/slices/narration/pronunciation-chunks.js +4 -3
  349. package/dist/slices/narration/pronunciation.js +6 -4
  350. package/dist/slices/narration/steering.js +4 -3
  351. package/dist/slices/notifications/notifier.js +4 -3
  352. package/dist/slices/notifications/rules.js +5 -2
  353. package/dist/slices/notifications/settings.js +4 -12
  354. package/dist/slices/notifications/subject.js +4 -3
  355. package/dist/slices/onboarding/copy.js +21 -3
  356. package/dist/slices/onboarding/first-run.js +16 -40
  357. package/dist/slices/onboarding/full-video.js +3 -2
  358. package/dist/slices/onboarding/install.js +6 -4
  359. package/dist/slices/onboarding/model.js +26 -37
  360. package/dist/slices/onboarding/packs.js +22 -22
  361. package/dist/slices/onboarding/preferred-model.js +14 -0
  362. package/dist/slices/onboarding/quick-short.js +105 -65
  363. package/dist/slices/onboarding/sample.js +4 -2
  364. package/dist/slices/onboarding/state.js +9 -11
  365. package/dist/slices/onboarding/template.js +8 -6
  366. package/dist/slices/outputs/add.js +3 -2
  367. package/dist/slices/outputs/service.js +2 -2
  368. package/dist/slices/patch-notes/library.js +4 -3
  369. package/dist/slices/play-drafts/convert.js +4 -0
  370. package/dist/slices/play-drafts/readiness.js +3 -3
  371. package/dist/slices/play-drafts/review-inputs.js +9 -3
  372. package/dist/slices/play-drafts/review.js +5 -4
  373. package/dist/slices/play-drafts/schema.js +4 -0
  374. package/dist/slices/play-drafts/service.js +17 -7
  375. package/dist/slices/project-templates/from-project.js +9 -2
  376. package/dist/slices/project-templates/next-chapter.js +2 -1
  377. package/dist/slices/project-templates/provider-defaults.js +22 -0
  378. package/dist/slices/project-templates/repo.js +6 -1
  379. package/dist/slices/project-templates/setup-sections.js +26 -0
  380. package/dist/slices/project-templates/setup.js +14 -1
  381. package/dist/slices/project-templates/stand-ins.js +22 -0
  382. package/dist/slices/rebuild/activity.js +2 -0
  383. package/dist/slices/rebuild/admission-repo.js +3 -2
  384. package/dist/slices/rebuild/narration-history.js +4 -5
  385. package/dist/slices/rebuild/narration-retry.js +2 -1
  386. package/dist/slices/rebuild/preview-details.js +32 -14
  387. package/dist/slices/rebuild/preview-plan.js +3 -8
  388. package/dist/slices/rebuild/recipe-build.js +8 -3
  389. package/dist/slices/rebuild/recipe-describe.js +3 -3
  390. package/dist/slices/rebuild/recipe-digest.js +58 -0
  391. package/dist/slices/rebuild/recipe-input-schema.js +10 -0
  392. package/dist/slices/rebuild/recipe-keywords.js +71 -0
  393. package/dist/slices/rebuild/recipe-legacy.js +5 -1
  394. package/dist/slices/rebuild/recipe-model.js +4 -0
  395. package/dist/slices/rebuild/recipe-narration-text.js +2 -1
  396. package/dist/slices/rebuild/recipe-preparation.js +4 -4
  397. package/dist/slices/rebuild/recipe-reference.js +8 -4
  398. package/dist/slices/rebuild/recipe-reviews.js +27 -7
  399. package/dist/slices/rebuild/recipe-save.js +8 -5
  400. package/dist/slices/rebuild/recipe-scenes.js +40 -11
  401. package/dist/slices/rebuild/recipe-shorts.js +8 -8
  402. package/dist/slices/rebuild/recipe-social.js +46 -0
  403. package/dist/slices/rebuild/recipe-text.js +64 -20
  404. package/dist/slices/rebuild/recipe-validation.js +102 -31
  405. package/dist/slices/rebuild/recipe-visual.js +55 -16
  406. package/dist/slices/rebuild/recipe-voices.js +3 -2
  407. package/dist/slices/rebuild/recipe-work.js +19 -7
  408. package/dist/slices/rebuild/recipe-youtube.js +4 -3
  409. package/dist/slices/rebuild/recovery-selection.js +3 -1
  410. package/dist/slices/rebuild/recovery.js +9 -8
  411. package/dist/slices/rebuild/remake-outdated.js +5 -5
  412. package/dist/slices/rebuild/repo.js +4 -3
  413. package/dist/slices/rebuild/review-promise.js +25 -0
  414. package/dist/slices/rebuild/review-redo.js +3 -2
  415. package/dist/slices/rebuild/runtime-admission.js +4 -3
  416. package/dist/slices/rebuild/runtime-agent-review.js +11 -5
  417. package/dist/slices/rebuild/runtime-animate.js +10 -9
  418. package/dist/slices/rebuild/runtime-article.js +7 -5
  419. package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
  420. package/dist/slices/rebuild/runtime-document.js +11 -13
  421. package/dist/slices/rebuild/runtime-export-bed.js +8 -12
  422. package/dist/slices/rebuild/runtime-export-edit.js +8 -16
  423. package/dist/slices/rebuild/runtime-export-inputs.js +12 -11
  424. package/dist/slices/rebuild/runtime-export-short.js +9 -5
  425. package/dist/slices/rebuild/runtime-export.js +38 -15
  426. package/dist/slices/rebuild/runtime-figure-card.js +2 -1
  427. package/dist/slices/rebuild/runtime-image.js +8 -12
  428. package/dist/slices/rebuild/runtime-instructions.js +2 -0
  429. package/dist/slices/rebuild/runtime-keywords.js +59 -0
  430. package/dist/slices/rebuild/runtime-lines.js +2 -11
  431. package/dist/slices/rebuild/runtime-local.js +17 -22
  432. package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
  433. package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
  434. package/dist/slices/rebuild/runtime-narration-text.js +13 -17
  435. package/dist/slices/rebuild/runtime-pictures.js +2 -4
  436. package/dist/slices/rebuild/runtime-piece-label.js +10 -6
  437. package/dist/slices/rebuild/runtime-plan.js +31 -5
  438. package/dist/slices/rebuild/runtime-provider.js +67 -25
  439. package/dist/slices/rebuild/runtime-publication.js +10 -9
  440. package/dist/slices/rebuild/runtime-review.js +39 -33
  441. package/dist/slices/rebuild/runtime-run.js +4 -1
  442. package/dist/slices/rebuild/runtime-shorts.js +31 -50
  443. package/dist/slices/rebuild/runtime-store.js +20 -10
  444. package/dist/slices/rebuild/runtime-subtitles.js +28 -25
  445. package/dist/slices/rebuild/runtime-voices.js +10 -16
  446. package/dist/slices/rebuild/runtime-youtube.js +14 -31
  447. package/dist/slices/rebuild/service-readiness.js +11 -3
  448. package/dist/slices/rebuild/transition-repo.js +6 -5
  449. package/dist/slices/rebuild/work-records.js +6 -0
  450. package/dist/slices/reruns/cascade.js +1 -2
  451. package/dist/slices/reruns/index.js +6 -9
  452. package/dist/slices/research/synthesis.js +3 -2
  453. package/dist/slices/reviews/external-model.js +4 -1
  454. package/dist/slices/reviews/external-repo.js +2 -1
  455. package/dist/slices/reviews/external-rows.js +2 -3
  456. package/dist/slices/reviews/holds.js +5 -4
  457. package/dist/slices/reviews/model.js +32 -11
  458. package/dist/slices/reviews/repo.js +2 -1
  459. package/dist/slices/reviews/rules.js +4 -3
  460. package/dist/slices/reviews/verdict.js +2 -1
  461. package/dist/slices/reviews/view.js +5 -2
  462. package/dist/slices/revisions/downloads.js +4 -5
  463. package/dist/slices/revisions/image-plan.js +1 -1
  464. package/dist/slices/revisions/mutation-assets.js +9 -5
  465. package/dist/slices/revisions/mutation-cues.js +2 -5
  466. package/dist/slices/revisions/mutations.js +3 -3
  467. package/dist/slices/revisions/repo.js +3 -1
  468. package/dist/slices/revisions/schema.js +1 -0
  469. package/dist/slices/revisions/view.js +20 -0
  470. package/dist/slices/run-cost/limits.js +5 -2
  471. package/dist/slices/run-cost/meter.js +12 -5
  472. package/dist/slices/run-cost/panel.js +8 -74
  473. package/dist/slices/run-cost/plan-readings.js +127 -0
  474. package/dist/slices/run-cost/plan-use.js +169 -0
  475. package/dist/slices/run-cost/pricing.js +3 -3
  476. package/dist/slices/run-cost/week.js +32 -4
  477. package/dist/slices/schedules/agenda.js +18 -7
  478. package/dist/slices/schedules/by-date.js +42 -0
  479. package/dist/slices/schedules/calendar.js +5 -0
  480. package/dist/slices/schedules/design-agenda.js +36 -0
  481. package/dist/slices/schedules/design-check.js +41 -0
  482. package/dist/slices/schedules/design-run.js +126 -0
  483. package/dist/slices/schedules/next-run.js +62 -0
  484. package/dist/slices/schedules/prepare.js +18 -2
  485. package/dist/slices/schedules/repo.js +30 -21
  486. package/dist/slices/schedules/rescore.js +35 -0
  487. package/dist/slices/schedules/scheduler.js +13 -3
  488. package/dist/slices/schedules/schema.js +57 -3
  489. package/dist/slices/schedules/score.js +107 -0
  490. package/dist/slices/schedules/service.js +57 -24
  491. package/dist/slices/schedules/topic-list.js +15 -0
  492. package/dist/slices/schedules/topic-scores.js +104 -0
  493. package/dist/slices/schedules/topics.js +53 -41
  494. package/dist/slices/settings/cli-paths.js +4 -6
  495. package/dist/slices/settings/first-run.js +8 -43
  496. package/dist/slices/settings/health.js +30 -15
  497. package/dist/slices/settings/key-test.js +1 -1
  498. package/dist/slices/settings/model-reach.js +3 -17
  499. package/dist/slices/settings/model.js +14 -2
  500. package/dist/slices/settings/playback.js +34 -23
  501. package/dist/slices/settings/probe-read.js +16 -0
  502. package/dist/slices/settings/repo.js +33 -0
  503. package/dist/slices/settings/tutorial.js +2 -2
  504. package/dist/slices/settings/voices.js +4 -12
  505. package/dist/slices/shorts/keep.js +2 -1
  506. package/dist/slices/shorts/pick.js +6 -18
  507. package/dist/slices/shorts/prompts.js +4 -14
  508. package/dist/slices/shorts/render.js +6 -2
  509. package/dist/slices/social/channel.js +44 -0
  510. package/dist/slices/social/defaults.js +17 -0
  511. package/dist/slices/social/due.js +36 -0
  512. package/dist/slices/social/extension.js +18 -0
  513. package/dist/slices/social/fit.js +115 -0
  514. package/dist/slices/social/limits.js +186 -0
  515. package/dist/slices/social/links.js +21 -0
  516. package/dist/slices/social/media.js +132 -0
  517. package/dist/slices/social/model.js +75 -0
  518. package/dist/slices/social/notice.js +19 -0
  519. package/dist/slices/social/pack.js +176 -0
  520. package/dist/slices/social/post-prompt.js +56 -0
  521. package/dist/slices/social/queue.js +31 -0
  522. package/dist/slices/social/repo.js +133 -0
  523. package/dist/slices/social/reshape.js +97 -0
  524. package/dist/slices/social/rules.js +5 -0
  525. package/dist/slices/social/schema.js +70 -0
  526. package/dist/slices/social/serve.js +51 -0
  527. package/dist/slices/social/service.js +129 -0
  528. package/dist/slices/social/settings.js +21 -0
  529. package/dist/slices/social/sources.js +114 -0
  530. package/dist/slices/social/state.js +110 -0
  531. package/dist/slices/social/text.js +149 -0
  532. package/dist/slices/storage/arrange.js +3 -1
  533. package/dist/slices/storage/assets.js +8 -10
  534. package/dist/slices/storage/backup-designs.js +74 -0
  535. package/dist/slices/storage/backup-export.js +8 -3
  536. package/dist/slices/storage/backup-format.js +10 -0
  537. package/dist/slices/storage/backup-import.js +22 -4
  538. package/dist/slices/storage/delete-project.js +6 -5
  539. package/dist/slices/storage/files-location.js +6 -8
  540. package/dist/slices/storage/layout.js +13 -2
  541. package/dist/slices/storage/model.js +3 -0
  542. package/dist/slices/storage/portable.js +17 -12
  543. package/dist/slices/storage/schema.js +2 -0
  544. package/dist/slices/storage/staging-refs.js +2 -1
  545. package/dist/slices/storage/staging.js +6 -9
  546. package/dist/slices/storage/trim.js +26 -9
  547. package/dist/slices/studio/calendar.js +7 -2
  548. package/dist/slices/studio/disclosure.js +4 -4
  549. package/dist/slices/studio/model.js +1 -1
  550. package/dist/slices/studio/pack.js +9 -8
  551. package/dist/slices/studio/pick.js +2 -11
  552. package/dist/slices/studio/plan.js +7 -16
  553. package/dist/slices/studio/queue.js +3 -14
  554. package/dist/slices/studio/releases.js +26 -0
  555. package/dist/slices/studio/settings.js +20 -57
  556. package/dist/slices/studio/videos.js +35 -4
  557. package/dist/slices/style-preview/render.js +37 -16
  558. package/dist/slices/style-preview/schema.js +14 -1
  559. package/dist/slices/style-preview/service.js +2 -1
  560. package/dist/slices/style-preview/settings.js +33 -5
  561. package/dist/slices/subtitles/captions.js +1 -1
  562. package/dist/slices/telemetry/collector-client.js +2 -4
  563. package/dist/slices/telemetry/flush.js +2 -4
  564. package/dist/slices/telemetry/model.js +0 -7
  565. package/dist/slices/telemetry/record.js +10 -3
  566. package/dist/slices/template-studio/anatomy-view.js +161 -0
  567. package/dist/slices/template-studio/anatomy.js +73 -0
  568. package/dist/slices/template-studio/bakeoff-make.js +225 -0
  569. package/dist/slices/template-studio/bakeoff-repo.js +83 -0
  570. package/dist/slices/template-studio/bakeoff.js +333 -0
  571. package/dist/slices/template-studio/budget.js +106 -0
  572. package/dist/slices/template-studio/cards.js +78 -0
  573. package/dist/slices/template-studio/checks.js +322 -0
  574. package/dist/slices/template-studio/document-sample.js +56 -0
  575. package/dist/slices/template-studio/edit.js +15 -0
  576. package/dist/slices/template-studio/for-all.js +161 -0
  577. package/dist/slices/template-studio/free-video.js +31 -0
  578. package/dist/slices/template-studio/free.js +176 -0
  579. package/dist/slices/template-studio/gate.js +40 -0
  580. package/dist/slices/template-studio/hidden.js +20 -0
  581. package/dist/slices/template-studio/jobs.js +79 -0
  582. package/dist/slices/template-studio/loudness.js +111 -0
  583. package/dist/slices/template-studio/make.js +40 -0
  584. package/dist/slices/template-studio/model.js +58 -0
  585. package/dist/slices/template-studio/pack-import.js +253 -0
  586. package/dist/slices/template-studio/pack-samples.js +60 -0
  587. package/dist/slices/template-studio/pack.js +207 -0
  588. package/dist/slices/template-studio/paid-view.js +66 -0
  589. package/dist/slices/template-studio/paid.js +355 -0
  590. package/dist/slices/template-studio/quote.js +155 -0
  591. package/dist/slices/template-studio/ready.js +104 -0
  592. package/dist/slices/template-studio/repo.js +134 -0
  593. package/dist/slices/template-studio/reviews-path.js +58 -0
  594. package/dist/slices/template-studio/runner.js +84 -0
  595. package/dist/slices/template-studio/save.js +236 -0
  596. package/dist/slices/template-studio/say-it-as.js +248 -0
  597. package/dist/slices/template-studio/schedule-gate.js +34 -0
  598. package/dist/slices/template-studio/schedule-price.js +32 -0
  599. package/dist/slices/template-studio/schedule-sample.js +91 -0
  600. package/dist/slices/template-studio/schema.js +243 -0
  601. package/dist/slices/template-studio/scope.js +124 -0
  602. package/dist/slices/template-studio/sections.js +176 -0
  603. package/dist/slices/template-studio/service.js +175 -0
  604. package/dist/slices/template-studio/status.js +191 -0
  605. package/dist/slices/template-studio/topic.js +223 -0
  606. package/dist/slices/thumbnail/by-llm.js +1 -1
  607. package/dist/slices/trash/designs.js +76 -0
  608. package/dist/slices/trash/model.js +13 -4
  609. package/dist/slices/trash/service.js +52 -2
  610. package/dist/slices/tutorials/library.js +3 -2
  611. package/dist/slices/uploads/repo.js +37 -1
  612. package/dist/slices/uploads/rules.js +3 -2
  613. package/dist/slices/video/ass-text.js +17 -0
  614. package/dist/slices/video/audio-export.js +2 -64
  615. package/dist/slices/video/edit-list.js +2 -2
  616. package/dist/slices/video/edit-settings.js +1 -1
  617. package/dist/slices/video/encoding.js +169 -0
  618. package/dist/slices/video/ffmpeg.js +23 -21
  619. package/dist/slices/video/figure-card.js +1 -15
  620. package/dist/slices/video/plan.js +2 -1
  621. package/dist/slices/video/slideshow.js +43 -18
  622. package/dist/slices/voices/attribution.js +3 -2
  623. package/dist/slices/voices/model.js +9 -8
  624. package/dist/slices/voices/palette.js +0 -3
  625. package/dist/slices/voices/script.js +2 -1
  626. package/dist/slices/youtube/answer.js +4 -16
  627. package/dist/slices/youtube/edits-repo.js +3 -12
  628. package/dist/tutorials/AI-CLIs.md +25 -25
  629. package/dist/tutorials/Agents-MCP.md +34 -33
  630. package/dist/tutorials/Assistant.md +42 -0
  631. package/dist/tutorials/Backups.md +7 -7
  632. package/dist/tutorials/Calendar.md +17 -25
  633. package/dist/tutorials/Cast-Library.md +19 -19
  634. package/dist/tutorials/Channels.md +42 -35
  635. package/dist/tutorials/Costs-and-Run-Cost.md +38 -40
  636. package/dist/tutorials/Create-Article.md +114 -0
  637. package/dist/tutorials/Create-Extras.md +112 -0
  638. package/dist/tutorials/Create-Images.md +165 -0
  639. package/dist/tutorials/Create-Narration.md +178 -0
  640. package/dist/tutorials/Create-Overview.md +244 -0
  641. package/dist/tutorials/Create-Video-and-Style.md +144 -0
  642. package/dist/tutorials/Docker.md +3 -3
  643. package/dist/tutorials/Document-Themes.md +32 -32
  644. package/dist/tutorials/Editing-a-Project.md +94 -94
  645. package/dist/tutorials/FAQ.md +18 -18
  646. package/dist/tutorials/First-Launch-and-Welcome.md +50 -64
  647. package/dist/tutorials/Home-and-Projects.md +115 -71
  648. package/dist/tutorials/Home.md +33 -33
  649. package/dist/tutorials/Install.md +14 -13
  650. package/dist/tutorials/Intros-and-Outros.md +33 -34
  651. package/dist/tutorials/Keyboard-Shortcuts-and-Command-Palette.md +62 -58
  652. package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
  653. package/dist/tutorials/Models.md +53 -21
  654. package/dist/tutorials/Multiple-Voices.md +41 -40
  655. package/dist/tutorials/Narration-Aliases-and-Glossary.md +14 -14
  656. package/dist/tutorials/Notifications.md +27 -17
  657. package/dist/tutorials/Other-Languages.md +15 -15
  658. package/dist/tutorials/PDF-Documents.md +38 -29
  659. package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
  660. package/dist/tutorials/Project-Page.md +118 -120
  661. package/dist/tutorials/Prompts-and-Templates.md +84 -0
  662. package/dist/tutorials/Prompts.md +48 -44
  663. package/dist/tutorials/Providers-and-Keys.md +105 -98
  664. package/dist/tutorials/Publishing-to-YouTube.md +31 -31
  665. package/dist/tutorials/Recovery-and-Retries.md +31 -31
  666. package/dist/tutorials/Remote-Access.md +63 -0
  667. package/dist/tutorials/Reviews-and-Checkpoints.md +98 -90
  668. package/dist/tutorials/Schedules.md +46 -27
  669. package/dist/tutorials/Settings-Reference.md +194 -174
  670. package/dist/tutorials/Shorts.md +34 -33
  671. package/dist/tutorials/Start-at-Login.md +3 -3
  672. package/dist/tutorials/Studio-Extension.md +22 -24
  673. package/dist/tutorials/Template-Studio.md +128 -0
  674. package/dist/tutorials/Templates.md +51 -77
  675. package/dist/tutorials/Trash.md +4 -4
  676. package/dist/tutorials/Troubleshooting.md +44 -44
  677. package/dist/tutorials/Uninstalling-and-Moving.md +5 -5
  678. package/dist/tutorials/Updating-and-Patch-Notes.md +18 -18
  679. package/dist/tutorials/Video-Editing.md +34 -34
  680. package/dist/tutorials/Where-Your-Files-Live.md +10 -10
  681. package/dist/tutorials/YouTube-Description.md +26 -26
  682. package/dist/tutorials/Your-First-Short.md +35 -35
  683. package/dist/tutorials/_Sidebar.md +19 -14
  684. package/dist/updater/work-in-progress.js +42 -12
  685. package/dist/web/assets/index-BNftKQrA.css +1 -0
  686. package/dist/web/assets/index-Cpa58woP.js +459 -0
  687. package/dist/web/assets/pdf-BKh8f7R6.js +56 -0
  688. package/dist/web/assets/pdf.worker.min-BmVo14Nb.mjs +28 -0
  689. package/dist/web/assets/pdf.worker.min-D7i8o3wR.js +1 -0
  690. package/dist/web/index.html +2 -2
  691. package/package.json +6 -2
  692. package/dist/slices/article/provided-entries.js +0 -66
  693. package/dist/slices/article/run.js +0 -145
  694. package/dist/slices/images/run.js +0 -234
  695. package/dist/slices/narration/legacy-plan.js +0 -58
  696. package/dist/slices/narration/run.js +0 -270
  697. package/dist/slices/rebuild/runtime-actions.js +0 -90
  698. package/dist/slices/research/run.js +0 -224
  699. package/dist/slices/subtitles/prepare.js +0 -194
  700. package/dist/slices/subtitles/transcript.js +0 -34
  701. package/dist/slices/thumbnail/run.js +0 -219
  702. package/dist/slices/video/audio-inputs.js +0 -33
  703. package/dist/slices/video/reuse-audio.js +0 -62
  704. package/dist/slices/video/run.js +0 -78
  705. package/dist/slices/video/write-export.js +0 -158
  706. package/dist/slices/video/write-subtitles.js +0 -59
  707. package/dist/tutorials/Library-Overview.md +0 -76
  708. package/dist/tutorials/Play-Images.md +0 -161
  709. package/dist/tutorials/Play-Narration.md +0 -167
  710. package/dist/tutorials/Play-Outputs.md +0 -109
  711. package/dist/tutorials/Play-Overview.md +0 -227
  712. package/dist/tutorials/Play-Title-and-Article.md +0 -136
  713. package/dist/tutorials/Play-Video-and-Style.md +0 -143
  714. package/dist/web/assets/index-BadsoORk.css +0 -1
  715. package/dist/web/assets/index-D8LqNsCl.js +0 -326
  716. package/dist/web/assets/pdf-T7MCwjIv.js +0 -54
  717. package/dist/web/assets/pdf.worker.min-Dswkl-cV.mjs +0 -29
  718. package/dist/web/assets/pdf.worker.min-zC6nfbxG.js +0 -1
@@ -1,10 +1,13 @@
1
1
  import { z } from "zod";
2
+ import { internalError } from "../../kernel/errors.js";
2
3
  import { redact } from "../../kernel/log.js";
3
4
  import { providerError } from "../../kernel/ports/model.js";
4
- import { httpFailure, internalError, missingKey, noImage, providerSaid, unreadable, } from "../explain.js";
5
- import { retryAfter } from "../retry-after.js";
5
+ import { createRows, editSettings } from "../../kernel/ports/settings-places.js";
6
+ import { httpFailure, noImage, providerSaid, unreadable } from "../explain.js";
7
+ import { failureText, httpProviderError, kindOfStatus, requireKey, safeJson, } from "../http-failure.js";
8
+ import { modelAccessOf } from "../model-access.js";
6
9
  import { downloadImage } from "./bytes.js";
7
- import { referencePictures, withReferences } from "./reference.js";
10
+ import { attachedPictures, promptFor } from "./reference.js";
8
11
  import { dataUri, downloadVideo } from "./video.js";
9
12
  // The HTTP gateway adapter for fal.ai: `fetch` and the downloader beside this file, no SDK.
10
13
  // `@fal-ai/client` would buy queue polling, which only the video clips need and which is three
@@ -60,6 +63,7 @@ const editModels = [
60
63
  function editEndpoint(model) {
61
64
  return editModels.includes(model) ? `${model}/edit` : undefined;
62
65
  }
66
+ export const falEditRefusal = "This fal.ai model can't edit a picture. Choose FLUX.2 or Nano Banana 2 on fal.ai, or Codex CLI, OpenAI or Google, under Made with … · change.";
63
67
  // Image-to-video runs on fal's queue, not the synchronous host: a clip takes one to five
64
68
  // minutes, and fal documents the queue as the way to call anything that slow. A request is
65
69
  // submitted, its status polled until it completes, and its answer fetched from the links the
@@ -104,19 +108,21 @@ export function falImage(deps) {
104
108
  // `image_urls`; only the models that have one are marked as taking a reference.
105
109
  // Cast pictures ride the same list; a model without an edit endpoint gets the cast in
106
110
  // words instead, since only the establishing image is something the user turned on.
107
- const pictures = referencePictures(req);
111
+ const pictures = attachedPictures(req);
108
112
  const edit = pictures.length === 0 ? undefined : editEndpoint(req.model);
113
+ if (req.edit !== undefined && edit === undefined)
114
+ throw providerError({ kind: "unsupported", message: falEditRefusal });
109
115
  if (req.reference !== undefined && edit === undefined)
110
116
  throw providerError({
111
117
  kind: "unsupported",
112
- message: "This fal.ai model can't use an establishing image as a reference. Choose FLUX.2 or Nano Banana 2 under Images → Model on Play or in Edit project → Providers, or set Establishing image to Off in the Images section.",
118
+ message: `This fal.ai model can't use an establishing image as a reference. Choose FLUX.2 or Nano Banana 2 as the image model in ${createRows.images} or ${editSettings.images}, or set Establishing image to Off there.`,
113
119
  });
114
120
  const response = await deps.fetch(`${falBase}/${edit ?? req.model}`, {
115
121
  method: "POST",
116
122
  signal: req.signal,
117
123
  headers: { Authorization: `Key ${keyOf(deps)}`, "Content-Type": "application/json" },
118
124
  body: JSON.stringify({
119
- prompt: withReferences(req.prompt, req, edit === undefined ? 0 : pictures.length),
125
+ prompt: promptFor(req.prompt, req, edit === undefined ? 0 : pictures.length),
120
126
  ...(edit === undefined
121
127
  ? {}
122
128
  : { image_urls: pictures.map((picture) => dataUri(picture.image)) }),
@@ -129,7 +135,7 @@ export function falImage(deps) {
129
135
  }),
130
136
  });
131
137
  if (!response.ok) {
132
- throw await failure(response);
138
+ throw await failure(response, "image request", true);
133
139
  }
134
140
  const answer = parse(await response.text());
135
141
  refused(answer, req.prompt);
@@ -162,7 +168,7 @@ export function falImage(deps) {
162
168
  }),
163
169
  });
164
170
  if (!submitted.ok)
165
- throw await failure(submitted, "video clip request");
171
+ throw await failure(submitted, "video clip request", true);
166
172
  const links = read(queued, await submitted.text());
167
173
  for (;;) {
168
174
  const status = await deps.fetch(links.status_url, { signal: req.signal, headers });
@@ -172,7 +178,7 @@ export function falImage(deps) {
172
178
  if (current.error)
173
179
  throw providerError({
174
180
  kind: "other",
175
- message: providerSaid("fal.ai", "could not make the video clip", redact(current.error), "Use Try again; if it keeps happening, choose another image-to-video model under Animate images in Edit project → Inputs → Look."),
181
+ message: providerSaid("fal.ai", "could not make the video clip", redact(current.error), `Use Try again; if it keeps happening, choose another image-to-video model under Animate images in ${editSettings.look}.`),
176
182
  });
177
183
  if (current.status === "COMPLETED")
178
184
  break;
@@ -198,12 +204,7 @@ function read(schema, text) {
198
204
  return parsed.data;
199
205
  }
200
206
  function keyOf(deps) {
201
- // `missing_key`, not `auth`, because that rule makes it terminal.
202
- const key = deps.key();
203
- if (key === undefined || key === "") {
204
- throw providerError({ kind: "missing_key", message: missingKey("fal.ai") });
205
- }
206
- return key;
207
+ return requireKey(deps.key(), "fal.ai");
207
208
  }
208
209
  // A content-policy refusal is final, named here and made terminal by the wrapper. fal declines
209
210
  // inside a 200 - the safety checker flags the image and hands back a blank one. With no
@@ -213,41 +214,16 @@ function refused(answer, prompt) {
213
214
  if (flags.length > 0 && flags.every((flagged) => flagged)) {
214
215
  throw providerError({
215
216
  kind: "refusal",
216
- message: `fal.ai's safety checker blocked the image for this prompt: "${redact(prompt)}". Reword the image prompt in the Images section of Edit project, or choose another image provider in its Providers section.`,
217
+ message: `fal.ai's safety checker blocked the image for this prompt: "${redact(prompt)}". Reword the image prompt in ${editSettings.images}, or choose another image service there.`,
217
218
  });
218
219
  }
219
220
  }
220
- // Only the adapter sees the vendor's status code, so only the adapter names the kind.
221
- function kindOf(status) {
222
- if (status === 401 || status === 403) {
223
- return "auth";
224
- }
225
- if (status === 429) {
226
- return "rate_limit";
227
- }
228
- // ceiling: everything else is `other` and is retried, so a 422 naming an input this model
229
- // does not take fails the same way four times over. A terminal "this will never work" kind
230
- // has to reach the port's error contract first, which is not this adapter's to widen.
231
- // The provider's own server failed; the same request may well succeed later.
232
- if (status >= 500)
233
- return "dropped";
234
- return "other";
235
- }
236
- async function failure(response, subject = "image request") {
237
- const text = await response.text().catch(() => "");
221
+ // `atModel`: the request went to the model's own address, so a 404 or 403 is about the model.
222
+ async function failure(response, subject = "image request", atModel = false) {
223
+ const text = await failureText(response);
238
224
  // The provider's own words, through the redactor - an error body may quote the key back.
239
225
  const message = redact(detailOf(text) || response.statusText);
240
- const retryAfterMs = retryAfter(response.headers.get("retry-after"));
241
- return providerError({
242
- kind: kindOf(response.status),
243
- message: httpFailure({
244
- provider: "fal.ai",
245
- status: response.status,
246
- detail: message,
247
- subject,
248
- }),
249
- ...(retryAfterMs === undefined ? {} : { retryAfterMs }),
250
- });
226
+ return httpProviderError(response, kindOfStatus(response.status), httpFailure({ provider: "fal.ai", status: response.status, detail: message, subject }), undefined, modelAccessOf(response.status, text, atModel));
251
227
  }
252
228
  function detailOf(text) {
253
229
  const parsed = errorBody.safeParse(safeJson(text));
@@ -270,11 +246,3 @@ function parse(text) {
270
246
  }
271
247
  return parsed.data;
272
248
  }
273
- function safeJson(text) {
274
- try {
275
- return JSON.parse(text);
276
- }
277
- catch {
278
- return undefined;
279
- }
280
- }
@@ -1,11 +1,13 @@
1
1
  import { z } from "zod";
2
2
  import { redact } from "../../kernel/log.js";
3
3
  import { providerError } from "../../kernel/ports/model.js";
4
- import { httpFailure, missingKey, noImage, quoted, refusedImage, unreadable } from "../explain.js";
5
- import { retryAfter } from "../retry-after.js";
4
+ import { editSettings } from "../../kernel/ports/settings-places.js";
5
+ import { httpFailure, noImage, quoted, refusedImage, unreadable } from "../explain.js";
6
+ import { failureText, httpProviderError, kindOfStatus, requireKey, safeJson, } from "../http-failure.js";
7
+ import { modelAccessOf } from "../model-access.js";
6
8
  import { describeBytes, sniffImage } from "./bytes.js";
7
9
  import { discoverGoogleImages } from "./models.js";
8
- import { referencePictures, withReferences } from "./reference.js";
10
+ import { attachedPictures, promptFor } from "./reference.js";
9
11
  // The HTTP gateway adapter for Google's own image generation, billed to a Gemini API key
10
12
  // rather than to a host reselling the same models. Like the OpenAI one it hands back the
11
13
  // bytes with the call, so there is no link to follow.
@@ -65,15 +67,15 @@ export function googleImage(deps) {
65
67
  model: req.model,
66
68
  // With an establishing image the input is two parts, the image first; the Gemini
67
69
  // image models draw with an input image as their reference.
68
- input: referencePictures(req).length === 0
70
+ input: attachedPictures(req).length === 0
69
71
  ? req.prompt
70
72
  : [
71
- ...referencePictures(req).map(({ image }) => ({
73
+ ...attachedPictures(req).map(({ image }) => ({
72
74
  type: "image",
73
75
  mime_type: image.mime,
74
76
  data: Buffer.from(image.bytes).toString("base64"),
75
77
  })),
76
- { type: "text", text: withReferences(req.prompt, req) },
78
+ { type: "text", text: promptFor(req.prompt, req) },
77
79
  ],
78
80
  // The stage sends Number as that many independent calls, one piece each, so one
79
81
  // image per request is what it asks for. Nothing about style is set: the stage
@@ -117,18 +119,13 @@ function decode(part) {
117
119
  const claimed = part.mime_type ?? "nothing";
118
120
  throw providerError({
119
121
  kind: "other",
120
- message: `Google sent back something that is not a PNG or JPEG image (labelled ${claimed}, but ${describeBytes(bytes)}). Use Try again; if it keeps happening, choose another image model in the Providers section of Edit project.`,
122
+ message: `Google sent back something that is not a PNG or JPEG image (labelled ${claimed}, but ${describeBytes(bytes)}). Use Try again; if it keeps happening, choose another image model in ${editSettings.images}.`,
121
123
  });
122
124
  }
123
125
  return { bytes, mime };
124
126
  }
125
127
  function keyOf(deps) {
126
- // `missing_key`, not `auth`, because that rule makes it terminal.
127
- const key = deps.key();
128
- if (key === undefined || key === "") {
129
- throw providerError({ kind: "missing_key", message: missingKey("Google") });
130
- }
131
- return key;
128
+ return requireKey(deps.key(), "Google");
132
129
  }
133
130
  // Only the adapter sees the vendor's status code, so only the adapter names the kind.
134
131
  function kindOf(status, named, message) {
@@ -141,27 +138,16 @@ function kindOf(status, named, message) {
141
138
  if (status === 400 && refusalWords.test(message)) {
142
139
  return "refusal";
143
140
  }
144
- if (status === 401 || status === 403) {
145
- return "auth";
146
- }
147
- if (status === 429) {
148
- // Interactions wraps quota failures in a string-coded error and exposes the limit
149
- // in the message. Zero allocated capacity cannot be fixed by waiting and retrying.
150
- if (/quota exceeded for metric:[^\r\n]*?\blimit:\s*0\s*(?:,|$)/im.test(message)) {
151
- return "unsupported";
152
- }
153
- return "rate_limit";
141
+ // Interactions wraps quota failures in a string-coded error and exposes the limit
142
+ // in the message. Zero allocated capacity cannot be fixed by waiting and retrying.
143
+ if (status === 429 &&
144
+ /quota exceeded for metric:[^\r\n]*?\blimit:\s*0\s*(?:,|$)/im.test(message)) {
145
+ return "unsupported";
154
146
  }
155
- // ceiling: everything else is `other` and is retried, so a prompt past the model's limit
156
- // fails the same way four times over. A terminal "this will never work" kind has to reach
157
- // the port's error contract first, which is not this adapter's to widen.
158
- // The provider's own server failed; the same request may well succeed later.
159
- if (status >= 500)
160
- return "dropped";
161
- return "other";
147
+ return kindOfStatus(status);
162
148
  }
163
149
  async function failure(response) {
164
- const text = await response.text().catch(() => "");
150
+ const text = await failureText(response);
165
151
  const parsed = errorBody.safeParse(safeJson(text));
166
152
  // The provider's own words, through the redactor - an error body may quote the key back.
167
153
  const named = parsed.success ? parsed.data.error.status : undefined;
@@ -170,24 +156,23 @@ async function failure(response) {
170
156
  const delay = parsed.success
171
157
  ? parsed.data.error.details?.find((one) => one["@type"] === "type.googleapis.com/google.rpc.RetryInfo")?.retryDelay
172
158
  : undefined;
173
- const retryAfterMs = retryAfter(response.headers.get("retry-after")) ?? googleRetryDelay(delay, message);
174
159
  const detail = message || response.statusText;
175
- return providerError({
176
- kind,
177
- message: kind === "unsupported"
178
- ? `Google gives this API key no image quota for this model${quoted(`error ${String(response.status)}`, detail)}. Retrying will not help: turn on billing for the key's project in Google AI Studio, or choose another image provider in the Providers section of Edit project.`
179
- : // PERMISSION_DENIED and FAILED_PRECONDITION also cover keys without access, billing
180
- // and region limits, so they read as a content refusal only when Google says so.
181
- kind === "refusal" && refusalWords.test(message)
182
- ? refusedImage("Google", detail)
183
- : httpFailure({
184
- provider: "Google",
185
- status: response.status,
186
- detail,
187
- subject: "image request",
188
- }),
189
- ...(retryAfterMs === undefined ? {} : { retryAfterMs }),
190
- });
160
+ const refused = kind === "refusal" && refusalWords.test(message);
161
+ return httpProviderError(response, kind, kind === "unsupported"
162
+ ? `Google gives this API key no image quota for this model${quoted(`error ${String(response.status)}`, detail)}. Retrying will not help: turn on billing for the key's project in Google AI Studio, or choose another image service in ${editSettings.images}.`
163
+ : // PERMISSION_DENIED and FAILED_PRECONDITION also cover keys without access, billing
164
+ // and region limits, so they read as a content refusal only when Google says so.
165
+ refused
166
+ ? refusedImage("Google", detail)
167
+ : httpFailure({
168
+ provider: "Google",
169
+ status: response.status,
170
+ detail,
171
+ subject: "image request",
172
+ }), googleRetryDelay(delay, message),
173
+ // A key that reads the model list but is denied or told "not found" here is denied the
174
+ // model the request names: Google answers a bad key with 400 API_KEY_INVALID.
175
+ refused ? undefined : modelAccessOf(response.status, `${named ?? ""} ${message}`, true));
191
176
  }
192
177
  function googleRetryDelay(delay, message) {
193
178
  const seconds = delay?.match(/^(\d+(?:\.\d+)?)s$/)?.[1] ??
@@ -207,11 +192,3 @@ function parse(text) {
207
192
  }
208
193
  return parsed.data;
209
194
  }
210
- function safeJson(text) {
211
- try {
212
- return JSON.parse(text);
213
- }
214
- catch {
215
- return undefined;
216
- }
217
- }
@@ -66,13 +66,13 @@ function requireKey(deps) {
66
66
  if (key === undefined || key === "")
67
67
  throw providerError({
68
68
  kind: "missing_key",
69
- message: "Save this provider's API key in Settings → Providers to load its models.",
69
+ message: "Save this provider's API key in Settings → Keys & services to load its models.",
70
70
  });
71
71
  return key;
72
72
  }
73
73
  function unavailable() {
74
74
  return providerError({
75
75
  kind: "other",
76
- message: "Slopify could not load this provider's model list. Check the API key in Settings → Providers and your internet connection, then refresh the list.",
76
+ message: "Slopify could not load this provider's model list. Check the API key in Settings → Keys & services and your internet connection, then refresh the list.",
77
77
  });
78
78
  }
@@ -1,11 +1,13 @@
1
1
  import { z } from "zod";
2
2
  import { redact } from "../../kernel/log.js";
3
3
  import { providerError } from "../../kernel/ports/model.js";
4
- import { httpFailure, missingKey, noImage, refusedImage, unreadable } from "../explain.js";
5
- import { retryAfter } from "../retry-after.js";
4
+ import { editSettings } from "../../kernel/ports/settings-places.js";
5
+ import { httpFailure, noImage, refusedImage, unreadable } from "../explain.js";
6
+ import { failureText, httpProviderError, kindOfStatus, requireKey, safeJson, } from "../http-failure.js";
7
+ import { modelAccessOf } from "../model-access.js";
6
8
  import { describeBytes, sniffImage } from "./bytes.js";
7
9
  import { discoverOpenAiImages } from "./models.js";
8
- import { referencePictures, withReferences } from "./reference.js";
10
+ import { attachedPictures, promptFor } from "./reference.js";
9
11
  // The HTTP gateway adapter for OpenAI's images endpoint: the platform's own `fetch` and
10
12
  // nothing else, because the whole call is one request. Unlike fal and Replicate this one
11
13
  // hands back the image itself - a GPT image model always answers with base64, never a URL -
@@ -56,7 +58,7 @@ export function openAiImage(deps) {
56
58
  id: "openai-image",
57
59
  models: () => discoverOpenAiImages(deps),
58
60
  generate: async (req) => {
59
- const pictures = referencePictures(req);
61
+ const pictures = attachedPictures(req);
60
62
  const response = pictures.length === 0
61
63
  ? await deps.fetch(`${openAiImagesBase}/images/generations`, {
62
64
  method: "POST",
@@ -96,11 +98,11 @@ export function openAiImage(deps) {
96
98
  };
97
99
  }
98
100
  // The edits endpoint takes several input images as repeated `image[]` parts: the establishing
99
- // image first, then the cast pictures.
101
+ // image (or, for a design's edit, the picture to change) first, then the cast pictures.
100
102
  function editForm(req, pictures) {
101
103
  const form = new FormData();
102
104
  form.set("model", req.model);
103
- form.set("prompt", withReferences(req.prompt, req));
105
+ form.set("prompt", promptFor(req.prompt, req));
104
106
  form.set("n", "1");
105
107
  form.set("size", sizeFor(req.model, req.aspect));
106
108
  for (const [index, { image }] of pictures.entries())
@@ -116,57 +118,37 @@ function decode(b64) {
116
118
  if (mime === undefined) {
117
119
  throw providerError({
118
120
  kind: "other",
119
- message: `OpenAI sent back something that is not a PNG or JPEG image (${describeBytes(bytes)}). Use Try again; if it keeps happening, choose another image model in the Providers section of Edit project.`,
121
+ message: `OpenAI sent back something that is not a PNG or JPEG image (${describeBytes(bytes)}). Use Try again; if it keeps happening, choose another image model in ${editSettings.images}.`,
120
122
  });
121
123
  }
122
124
  return { bytes, mime };
123
125
  }
124
126
  function keyOf(deps) {
125
- // `missing_key`, not `auth`, because that rule makes it terminal.
126
- const key = deps.key();
127
- if (key === undefined || key === "") {
128
- throw providerError({ kind: "missing_key", message: missingKey("OpenAI") });
129
- }
130
- return key;
127
+ return requireKey(deps.key(), "OpenAI");
131
128
  }
132
129
  // Only the adapter sees the vendor's status code, so only the adapter names the kind.
133
130
  function kindOf(status, code) {
134
131
  if (code !== undefined && code !== null && refusalCodes.includes(code)) {
135
132
  return "refusal";
136
133
  }
137
- if (status === 401 || status === 403) {
138
- return "auth";
139
- }
140
- if (status === 429) {
141
- return "rate_limit";
142
- }
143
- // ceiling: everything else is `other` and is retried, so a prompt past the model's length
144
- // limit fails the same way four times over. A terminal "this will never work" kind has to
145
- // reach the port's error contract first, which is not this adapter's to widen.
146
- // The provider's own server failed; the same request may well succeed later.
147
- if (status >= 500)
148
- return "dropped";
149
- return "other";
134
+ return kindOfStatus(status);
150
135
  }
151
136
  async function failure(response) {
152
- const text = await response.text().catch(() => "");
137
+ const text = await failureText(response);
153
138
  const parsed = errorBody.safeParse(safeJson(text));
154
139
  // The provider's own words, through the redactor - an error body may quote the key back.
155
140
  const message = redact(parsed.success ? parsed.data.error.message : text.trim() || response.statusText);
156
- const retryAfterMs = retryAfter(response.headers.get("retry-after"));
157
141
  const kind = kindOf(response.status, parsed.success ? parsed.data.error.code : undefined);
158
- return providerError({
159
- kind,
160
- message: kind === "refusal"
161
- ? refusedImage("OpenAI", message)
162
- : httpFailure({
163
- provider: "OpenAI",
164
- status: response.status,
165
- detail: message,
166
- subject: "image request",
167
- }),
168
- ...(retryAfterMs === undefined ? {} : { retryAfterMs }),
169
- });
142
+ return httpProviderError(response, kind, kind === "refusal"
143
+ ? refusedImage("OpenAI", message)
144
+ : httpFailure({
145
+ provider: "OpenAI",
146
+ status: response.status,
147
+ detail: message,
148
+ subject: "image request",
149
+ }), undefined, kind === "refusal"
150
+ ? undefined
151
+ : modelAccessOf(response.status, `${parsed.success ? (parsed.data.error.code ?? "") : ""} ${message}`));
170
152
  }
171
153
  function parse(text) {
172
154
  const parsed = generated.safeParse(safeJson(text));
@@ -178,11 +160,3 @@ function parse(text) {
178
160
  }
179
161
  return parsed.data;
180
162
  }
181
- function safeJson(text) {
182
- try {
183
- return JSON.parse(text);
184
- }
185
- catch {
186
- return undefined;
187
- }
188
- }
@@ -39,3 +39,39 @@ export function withReferences(prompt, req, limit = Number.POSITIVE_INFINITY) {
39
39
  function describe(description) {
40
40
  return description.trim() === "" ? "" : ` (${description.trim()})`;
41
41
  }
42
+ // What an edit model is told about the first attached picture: it is the canvas to change,
43
+ // the opposite of a reference.
44
+ export const editNote = "Change the first attached image as follows. Keep everything the instruction does not mention exactly as it is: people, faces, composition and framing.";
45
+ // The pictures an edit request attaches: the picture to change, then each cast member's
46
+ // pictures. An edit never sends an establishing image.
47
+ export function editPictures(req) {
48
+ return [
49
+ ...(req.edit === undefined ? [] : [{ image: req.edit.source }]),
50
+ ...(req.cast ?? []).flatMap((member) => member.images.map((image) => ({ image, member: member.name }))),
51
+ ];
52
+ }
53
+ // The prompt an edit request sends with the first `limit` of `editPictures(req)` attached.
54
+ export function withEditInstruction(instruction, req, limit = Number.POSITIVE_INFINITY) {
55
+ const sent = editPictures(req).slice(0, limit);
56
+ const lines = [editNote];
57
+ for (const [index, picture] of sent.entries()) {
58
+ const member = req.cast?.find((row) => row.name === picture.member);
59
+ if (member !== undefined)
60
+ lines.push(`Image ${String(index + 1)} shows ${member.name}${describe(member.description)}: draw ${member.name} to look exactly like this.`);
61
+ }
62
+ const shown = new Set(sent.flatMap((picture) => picture.member ?? []));
63
+ for (const member of req.cast ?? [])
64
+ if (!shown.has(member.name))
65
+ lines.push(`${member.name} appears in this image${describe(member.description)}.`);
66
+ return `${lines.join("\n")}\n\n${instruction}`;
67
+ }
68
+ // What an adapter attaches and says: an edit's pictures and instruction, or, for every other
69
+ // request, exactly what it always attached and said.
70
+ export function attachedPictures(req) {
71
+ return req.edit === undefined ? referencePictures(req) : editPictures(req);
72
+ }
73
+ export function promptFor(prompt, req, limit = Number.POSITIVE_INFINITY) {
74
+ return req.edit === undefined
75
+ ? withReferences(prompt, req, limit)
76
+ : withEditInstruction(prompt, req, limit);
77
+ }
@@ -1,8 +1,10 @@
1
1
  import { z } from "zod";
2
2
  import { redact } from "../../kernel/log.js";
3
3
  import { providerError } from "../../kernel/ports/model.js";
4
- import { httpFailure, missingKey, noImage, providerSaid, refusedImage, unreadable, } from "../explain.js";
5
- import { retryAfter } from "../retry-after.js";
4
+ import { createRows, editSettings } from "../../kernel/ports/settings-places.js";
5
+ import { httpFailure, noImage, providerSaid, refusedImage, unreadable } from "../explain.js";
6
+ import { failureText, httpProviderError, kindOfStatus, requireKey, safeJson, } from "../http-failure.js";
7
+ import { modelAccessOf } from "../model-access.js";
6
8
  import { downloadImage } from "./bytes.js";
7
9
  import { withReferences } from "./reference.js";
8
10
  import { dataUri, downloadVideo } from "./video.js";
@@ -37,6 +39,7 @@ const errorBody = z.object({ detail: z.string().optional(), title: z.string().op
37
39
  // `canceled` cannot happen here - nothing cancels a prediction this app made - but reading
38
40
  // it as terminal beats polling forever.
39
41
  const settled = ["succeeded", "failed", "canceled"];
42
+ export const replicateEditRefusal = "Replicate's image models can't edit a picture. Choose Codex CLI, OpenAI, Google, or FLUX.2 or Nano Banana 2 on fal.ai under Made with … · change.";
40
43
  export function replicateImage(deps) {
41
44
  return {
42
45
  id: "replicate",
@@ -44,10 +47,12 @@ export function replicateImage(deps) {
44
47
  generate: async (req) => {
45
48
  // The Replicate models listed take no input image to draw from (the FLUX image inputs
46
49
  // copy the picture's composition), so an establishing image is refused, not dropped.
50
+ if (req.edit !== undefined)
51
+ throw providerError({ kind: "unsupported", message: replicateEditRefusal });
47
52
  if (req.reference !== undefined)
48
53
  throw providerError({
49
54
  kind: "unsupported",
50
- message: "Replicate's image models can't use an establishing image as a reference. Choose Codex CLI, OpenAI, Google or fal.ai under Images → Provider on Play or in Edit project → Providers, or set Establishing image to Off in the Images section.",
55
+ message: `Replicate's image models can't use an establishing image as a reference. Choose Codex CLI, OpenAI, Google or fal.ai as the image service in ${createRows.images} or ${editSettings.images}, or set Establishing image to Off there.`,
51
56
  });
52
57
  const response = await deps.fetch(`${replicateBase}/models/${req.model}/predictions`, {
53
58
  method: "POST",
@@ -70,7 +75,7 @@ export function replicateImage(deps) {
70
75
  }),
71
76
  });
72
77
  if (!response.ok) {
73
- throw await failure(response);
78
+ throw await failure(response, "image request", true);
74
79
  }
75
80
  const url = await settle(deps, parse(await response.text()), req.signal);
76
81
  // The download rides inside the attempt: a link that 404s is a failed attempt.
@@ -100,7 +105,7 @@ export function replicateImage(deps) {
100
105
  }),
101
106
  });
102
107
  if (!response.ok)
103
- throw await failure(response, "video clip request");
108
+ throw await failure(response, "video clip request", true);
104
109
  const url = await settle(deps, parse(await response.text()), req.signal);
105
110
  return await downloadVideo({
106
111
  fetch: deps.fetch,
@@ -168,50 +173,25 @@ function declined(current) {
168
173
  kind: refusal ? "refusal" : "other",
169
174
  message: refusal
170
175
  ? refusedImage("Replicate", message)
171
- : providerSaid("Replicate", "could not make the image", message, "Use Try again; if it keeps happening, reword the image prompt in the Images section of Edit project or choose another image model in its Providers section."),
176
+ : providerSaid("Replicate", "could not make the image", message, `Use Try again; if it keeps happening, reword the image prompt in ${editSettings.images} or choose another image model there.`),
172
177
  });
173
178
  }
174
179
  function auth(deps) {
175
- // `missing_key`, not `auth`, because that rule makes it terminal.
176
- const key = deps.key();
177
- if (key === undefined || key === "") {
178
- throw providerError({ kind: "missing_key", message: missingKey("Replicate") });
179
- }
180
- return { Authorization: `Bearer ${key}` };
180
+ return { Authorization: `Bearer ${requireKey(deps.key(), "Replicate")}` };
181
181
  }
182
- // Only the adapter sees the vendor's status code, so only the adapter names the kind.
183
- function kindOf(status) {
184
- if (status === 401 || status === 403) {
185
- return "auth";
186
- }
187
- if (status === 429) {
188
- return "rate_limit";
189
- }
190
- // ceiling: everything else is `other` and is retried, so a 402 with no credit left fails the
191
- // same way four times over. A terminal "this will never work" kind has to reach the port's
192
- // error contract first, which is not this adapter's to widen.
193
- // The provider's own server failed; the same request may well succeed later.
194
- if (status >= 500)
195
- return "dropped";
196
- return "other";
197
- }
198
- async function failure(response, subject = "image request") {
199
- const text = await response.text().catch(() => "");
182
+ // `atModel`: the request went to the model's own address, so a 404 or 403 is about the model.
183
+ async function failure(response, subject = "image request", atModel = false) {
184
+ const text = await failureText(response);
200
185
  const parsed = errorBody.safeParse(safeJson(text));
201
186
  // The provider's own words, through the redactor - an error body may quote the key back.
202
187
  const detail = parsed.success ? (parsed.data.detail ?? parsed.data.title) : undefined;
203
188
  const message = redact(detail ?? text.trim());
204
- const retryAfterMs = retryAfter(response.headers.get("retry-after"));
205
- return providerError({
206
- kind: kindOf(response.status),
207
- message: httpFailure({
208
- provider: "Replicate",
209
- status: response.status,
210
- detail: message || response.statusText,
211
- subject,
212
- }),
213
- ...(retryAfterMs === undefined ? {} : { retryAfterMs }),
214
- });
189
+ return httpProviderError(response, kindOfStatus(response.status), httpFailure({
190
+ provider: "Replicate",
191
+ status: response.status,
192
+ detail: message || response.statusText,
193
+ subject,
194
+ }), undefined, modelAccessOf(response.status, text, atModel));
215
195
  }
216
196
  function parse(text) {
217
197
  const parsed = prediction.safeParse(safeJson(text));
@@ -223,11 +203,3 @@ function parse(text) {
223
203
  }
224
204
  return parsed.data;
225
205
  }
226
- function safeJson(text) {
227
- try {
228
- return JSON.parse(text);
229
- }
230
- catch {
231
- return undefined;
232
- }
233
- }
@@ -1,4 +1,5 @@
1
1
  import { providerError } from "../../kernel/ports/model.js";
2
+ import { editSettings } from "../../kernel/ports/settings-places.js";
2
3
  import { describeBytes } from "./bytes.js";
3
4
  // What the two image-to-video adapters share: the still goes up inline as a data URI (the
4
5
  // render sends a small JPEG, `slices/rebuild/runtime-animate.ts`), and the clip comes back
@@ -22,7 +23,7 @@ export async function downloadVideo(download) {
22
23
  if (!sniffVideo(bytes))
23
24
  throw providerError({
24
25
  kind: "other",
25
- message: `${download.provider} sent back something that is not an MP4 video clip (${describeBytes(bytes)}). Use Try again; if it keeps happening, choose another image-to-video model under Animate images in Edit project → Inputs → Look.`,
26
+ message: `${download.provider} sent back something that is not an MP4 video clip (${describeBytes(bytes)}). Use Try again; if it keeps happening, choose another image-to-video model under Animate images in ${editSettings.look}.`,
26
27
  });
27
28
  return { bytes, mime: "video/mp4" };
28
29
  }