@gentbajko/slopify 3.25.8 → 4.0.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.
- package/dist/adapters/account-limits.js +30 -0
- package/dist/adapters/alignment/cache.js +3 -5
- package/dist/adapters/alignment/ctc.js +1 -2
- package/dist/adapters/alignment/lock.js +4 -3
- package/dist/adapters/alignment/multilingual.js +0 -3
- package/dist/adapters/alignment/prefetch.js +2 -1
- package/dist/adapters/alignment/worker.js +2 -1
- package/dist/adapters/explain.js +0 -3
- package/dist/adapters/ffmpeg.js +19 -1
- package/dist/adapters/host-cli/index.js +19 -3
- package/dist/adapters/http-failure.js +53 -0
- package/dist/adapters/image/codex.js +36 -4
- package/dist/adapters/image/fal.js +17 -50
- package/dist/adapters/image/google.js +31 -55
- package/dist/adapters/image/openai.js +20 -47
- package/dist/adapters/image/reference.js +36 -0
- package/dist/adapters/image/replicate.js +18 -47
- package/dist/adapters/interest/search-interest.js +113 -0
- package/dist/adapters/key-probes.js +53 -2
- package/dist/adapters/llm/antigravity.js +4 -0
- package/dist/adapters/llm/assistant-cli.js +388 -0
- package/dist/adapters/llm/child-session.js +83 -0
- package/dist/adapters/llm/claude-code-models.js +51 -98
- package/dist/adapters/llm/claude-code.js +13 -2
- package/dist/adapters/llm/codex-limits.js +27 -68
- package/dist/adapters/llm/codex-server-models.js +61 -109
- package/dist/adapters/llm/codex.js +12 -1
- package/dist/adapters/llm/openrouter.js +10 -47
- package/dist/adapters/llm/run-cli.js +6 -22
- package/dist/adapters/llm/sse-lines.js +5 -1
- package/dist/adapters/model-access.js +37 -0
- package/dist/adapters/tts/cartesia.js +15 -46
- package/dist/adapters/tts/elevenlabs.js +20 -52
- package/dist/adapters/tts/gemini.js +19 -40
- package/dist/adapters/tts/inworld-async.js +4 -1
- package/dist/adapters/tts/inworld.js +3 -0
- package/dist/adapters/tts/openai.js +20 -50
- package/dist/assets/models-lifecycle.yaml +6 -0
- package/dist/assistant-wiring.js +60 -0
- package/dist/autopilot-timers.js +59 -0
- package/dist/catalog/lifecycle.js +52 -0
- package/dist/catalog/propose.js +204 -0
- package/dist/catalog/registry.js +3 -1
- package/dist/catalog/schema.js +2 -0
- package/dist/catalog/store.js +39 -0
- package/dist/edge/autostart/native.js +3 -5
- package/dist/edge/autostart/prompt.js +2 -1
- package/dist/edge/autostart/service.js +3 -4
- package/dist/edge/cli-args.js +3 -4
- package/dist/edge/cli.js +2 -1
- package/dist/edge/docker-install/apply.js +11 -11
- package/dist/edge/docker-install/run.js +2 -1
- package/dist/edge/docker-install/state.js +4 -3
- package/dist/edge/docker-install/tree.js +2 -4
- package/dist/edge/docker-install/volume.js +3 -2
- package/dist/edge/docker.js +5 -4
- package/dist/edge/events/hub.js +5 -5
- package/dist/edge/http/actions.js +4 -25
- package/dist/edge/http/actor.js +5 -3
- package/dist/edge/http/app.js +85 -10
- package/dist/edge/http/assistant.js +127 -0
- package/dist/edge/http/audio-preview.js +4 -11
- package/dist/edge/http/auditions.js +1 -1
- package/dist/edge/http/autostart.js +5 -5
- package/dist/edge/http/backups.js +1 -3
- package/dist/edge/http/channel-memory.js +7 -20
- package/dist/edge/http/channels.js +13 -26
- package/dist/edge/http/checkpoints.js +33 -17
- package/dist/edge/http/design-templates.js +167 -0
- package/dist/edge/http/designs.js +178 -0
- package/dist/edge/http/diagnostics.js +5 -1
- package/dist/edge/http/document-themes.js +2 -11
- package/dist/edge/http/draft-files.js +1 -3
- package/dist/edge/http/draft-problem.js +4 -9
- package/dist/edge/http/drafts.js +3 -3
- package/dist/edge/http/entries.js +6 -9
- package/dist/edge/http/extension-auth.js +27 -0
- package/dist/edge/http/external-reviews.js +12 -11
- package/dist/edge/http/files.js +5 -11
- package/dist/edge/http/folder-location.js +1 -4
- package/dist/edge/http/fonts.js +0 -7
- package/dist/edge/http/home.js +38 -13
- package/dist/edge/http/host-cli.js +18 -8
- package/dist/edge/http/ids.js +8 -0
- package/dist/edge/http/keywords.js +35 -0
- package/dist/edge/http/model-checks.js +132 -0
- package/dist/edge/http/narration-peaks.js +5 -13
- package/dist/edge/http/onboarding.js +1 -14
- package/dist/edge/http/open-folder.js +5 -10
- package/dist/edge/http/outputs.js +4 -12
- package/dist/edge/http/patch-notes.js +4 -10
- package/dist/edge/http/planning.js +2 -6
- package/dist/edge/http/problem.js +2 -4
- package/dist/edge/http/project-create.js +1 -0
- package/dist/edge/http/project-templates.js +29 -17
- package/dist/edge/http/projects.js +2 -12
- package/dist/edge/http/prompts.js +7 -14
- package/dist/edge/http/pronunciations.js +1 -2
- package/dist/edge/http/providers.js +39 -24
- package/dist/edge/http/refusal.js +29 -0
- package/dist/edge/http/remote-access.js +40 -0
- package/dist/edge/http/remote-guard.js +71 -0
- package/dist/edge/http/request-guard.js +91 -0
- package/dist/edge/http/reviews.js +11 -24
- package/dist/edge/http/revision-files.js +5 -10
- package/dist/edge/http/revisions.js +10 -15
- package/dist/edge/http/run-cost.js +1 -2
- package/dist/edge/http/same-page.js +80 -0
- package/dist/edge/http/schedules.js +59 -32
- package/dist/edge/http/settings.js +22 -13
- package/dist/edge/http/social.js +282 -0
- package/dist/edge/http/staging.js +2 -4
- package/dist/edge/http/storage-files.js +5 -7
- package/dist/edge/http/storage.js +23 -23
- package/dist/edge/http/studio.js +23 -50
- package/dist/edge/http/style-preview.js +1 -4
- package/dist/edge/http/subtitles.js +3 -17
- package/dist/edge/http/template-studio.js +433 -0
- package/dist/edge/http/trash.js +10 -11
- package/dist/edge/http/tutorial.js +1 -2
- package/dist/edge/http/tutorials.js +5 -11
- package/dist/edge/http/update.js +7 -13
- package/dist/edge/http/waveform.js +3 -6
- package/dist/edge/http/youtube-edits.js +2 -3
- package/dist/edge/mcp/assistant.js +279 -0
- package/dist/edge/mcp/attribution.js +8 -2
- package/dist/edge/mcp/call-route.js +11 -2
- package/dist/edge/mcp/excluded-routes.js +25 -0
- package/dist/edge/mcp/http.js +11 -2
- package/dist/edge/mcp/instructions.js +5 -3
- package/dist/edge/mcp/library-tools.js +1 -0
- package/dist/edge/mcp/route-tool.js +35 -15
- package/dist/edge/mcp/server.js +13 -8
- package/dist/edge/mcp/tools-channels.js +2 -0
- package/dist/edge/mcp/tools-designs.js +165 -0
- package/dist/edge/mcp/tools-library.js +14 -2
- package/dist/edge/mcp/tools-planning.js +23 -4
- package/dist/edge/mcp/tools-projects.js +28 -1
- package/dist/edge/mcp/tools-runs.js +14 -1
- package/dist/edge/mcp/tools-schedules.js +28 -4
- package/dist/edge/mcp/tools-setup.js +61 -3
- package/dist/edge/mcp/tools-social.js +46 -0
- package/dist/edge/mcp/tools-storage.js +8 -0
- package/dist/edge/mcp/tools-template-studio.js +166 -0
- package/dist/edge/mcp/tools.js +6 -0
- package/dist/edge/remote-access/cli.js +71 -0
- package/dist/edge/remote-access/model.js +32 -0
- package/dist/edge/remote-access/rules.js +207 -0
- package/dist/edge/remote-access/service.js +203 -0
- package/dist/edge/remote-access/store.js +44 -0
- package/dist/edge/remote-access/views.js +43 -0
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/host-cli/install.js +2 -2
- package/dist/host-cli/open-folder.js +2 -2
- package/dist/host-cli/paths.js +2 -4
- package/dist/host-cli/server.js +4 -4
- package/dist/host-cli/service.js +3 -3
- package/dist/host-cli/status.js +7 -7
- package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
- package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
- package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
- package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
- package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
- package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
- package/dist/kernel/db/migrations/0070-designs.sql +53 -0
- package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
- package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
- package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
- package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
- package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
- package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
- package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
- package/dist/kernel/db/tx.js +2 -4
- package/dist/kernel/errors.js +27 -1
- package/dist/kernel/json-answer.js +15 -0
- package/dist/kernel/lock.js +4 -9
- package/dist/kernel/paths.js +8 -0
- package/dist/kernel/ports/assistant-cli.js +4 -0
- package/dist/kernel/ports/host-cli.js +3 -0
- package/dist/kernel/ports/interest.js +4 -0
- package/dist/kernel/ports/languages.js +0 -3
- package/dist/kernel/ports/model.js +2 -0
- package/dist/kernel/runner/attempt.js +3 -1
- package/dist/kernel/runner/audition.js +3 -1
- package/dist/kernel/runner/checkpoint-authority.js +2 -1
- package/dist/kernel/runner/index.js +8 -10
- package/dist/kernel/runner/model-access.js +40 -0
- package/dist/kernel/runner/model-check.js +153 -0
- package/dist/kernel/runner/providers.js +15 -10
- package/dist/kernel/runner/standalone.js +9 -5
- package/dist/main.js +334 -19
- package/dist/model-checks.js +166 -0
- package/dist/patch-notes/3.25.9.md +5 -0
- package/dist/patch-notes/4.0.0.md +51 -0
- package/dist/patch-notes/index.json +12 -0
- package/dist/slices/admission/heads.js +2 -1
- package/dist/slices/admission/repo.js +2 -1
- package/dist/slices/admission/rules.js +43 -8
- package/dist/slices/admission/schema.js +8 -0
- package/dist/slices/admission/stage-writes.js +0 -3
- package/dist/slices/admission/start.js +48 -31
- package/dist/slices/admission/substitute.js +7 -4
- package/dist/slices/agents/attention-posts.js +31 -0
- package/dist/slices/agents/attention-templates.js +33 -0
- package/dist/slices/agents/attention.js +10 -1
- package/dist/slices/agents/connection.js +2 -6
- package/dist/slices/agents/model.js +6 -3
- package/dist/slices/agents/repo.js +15 -7
- package/dist/slices/article/continuation.js +0 -63
- package/dist/slices/article/plain.js +3 -2
- package/dist/slices/article/segments.js +2 -62
- package/dist/slices/assistant/access.js +1 -0
- package/dist/slices/assistant/asks.js +80 -0
- package/dist/slices/assistant/cost.js +54 -0
- package/dist/slices/assistant/gate.js +222 -0
- package/dist/slices/assistant/model.js +79 -0
- package/dist/slices/assistant/names.js +23 -0
- package/dist/slices/assistant/prompt.js +74 -0
- package/dist/slices/assistant/repo.js +74 -0
- package/dist/slices/assistant/tokens.js +18 -0
- package/dist/slices/assistant/turn.js +342 -0
- package/dist/slices/autopilot/buffer.js +76 -0
- package/dist/slices/autopilot/model.js +14 -0
- package/dist/slices/autopilot/notify.js +27 -0
- package/dist/slices/autopilot/repo.js +34 -0
- package/dist/slices/autopilot/signals.js +194 -0
- package/dist/slices/autopilot/warnings.js +85 -0
- package/dist/slices/autopilot/weekly.js +100 -0
- package/dist/slices/backups/files.js +2 -6
- package/dist/slices/backups/repo.js +3 -15
- package/dist/slices/backups/service.js +4 -3
- package/dist/slices/channels/cast-images.js +2 -1
- package/dist/slices/channels/model.js +0 -1
- package/dist/slices/channels/rebrand.js +0 -3
- package/dist/slices/channels/repo.js +4 -0
- package/dist/slices/channels/schema.js +6 -0
- package/dist/slices/channels/service.js +10 -0
- package/dist/slices/channels/videos.js +2 -14
- package/dist/slices/checkpoints/index.js +0 -1
- package/dist/slices/control/providers.js +0 -26
- package/dist/slices/designs/artwork.js +66 -0
- package/dist/slices/designs/budget.js +23 -0
- package/dist/slices/designs/calls.js +124 -0
- package/dist/slices/designs/check-context.js +38 -0
- package/dist/slices/designs/check-text.js +43 -0
- package/dist/slices/designs/fields.js +88 -0
- package/dist/slices/designs/frames.js +34 -0
- package/dist/slices/designs/gate.js +128 -0
- package/dist/slices/designs/layout.js +293 -0
- package/dist/slices/designs/model.js +35 -0
- package/dist/slices/designs/pdf-job.js +23 -0
- package/dist/slices/designs/pdf-pages.js +30 -0
- package/dist/slices/designs/pdf-runner.js +68 -0
- package/dist/slices/designs/pdf-worker.js +24 -0
- package/dist/slices/designs/picture-size.js +79 -0
- package/dist/slices/designs/pictures.js +55 -0
- package/dist/slices/designs/quote.js +24 -0
- package/dist/slices/designs/render-args.js +36 -0
- package/dist/slices/designs/render-input.js +59 -0
- package/dist/slices/designs/render.js +215 -0
- package/dist/slices/designs/repo.js +101 -0
- package/dist/slices/designs/requests.js +80 -0
- package/dist/slices/designs/runner.js +239 -0
- package/dist/slices/designs/sample-repo.js +91 -0
- package/dist/slices/designs/sample.js +222 -0
- package/dist/slices/designs/schema.js +87 -0
- package/dist/slices/designs/sections.js +44 -0
- package/dist/slices/designs/service.js +233 -0
- package/dist/slices/designs/steps-repo.js +102 -0
- package/dist/slices/designs/studio-kind.js +39 -0
- package/dist/slices/designs/template-checks.js +44 -0
- package/dist/slices/designs/template-make.js +118 -0
- package/dist/slices/designs/templates.js +218 -0
- package/dist/slices/document/fonts.js +2 -1
- package/dist/slices/episodes/summarize.js +5 -1
- package/dist/slices/estimate/index.js +45 -7
- package/dist/slices/fonts/catalog.js +3 -2
- package/dist/slices/fonts/discovery.js +3 -2
- package/dist/slices/fonts/files.js +2 -6
- package/dist/slices/fonts/index.js +0 -1
- package/dist/slices/fonts/sfnt.js +45 -10
- package/dist/slices/images/appearance.js +6 -15
- package/dist/slices/images/scenes.js +100 -27
- package/dist/slices/keywords/digest.js +84 -0
- package/dist/slices/keywords/facts.js +92 -0
- package/dist/slices/keywords/fill.js +80 -0
- package/dist/slices/keywords/model.js +75 -0
- package/dist/slices/keywords/rules.js +187 -0
- package/dist/slices/keywords/schema.js +28 -0
- package/dist/slices/keywords/specs.js +260 -0
- package/dist/slices/keywords/values.js +74 -0
- package/dist/slices/library/lint.js +29 -12
- package/dist/slices/library/model.js +2 -0
- package/dist/slices/library/photorealistic.js +4 -12
- package/dist/slices/library/rename.js +9 -7
- package/dist/slices/library/save.js +14 -10
- package/dist/slices/library/slots.js +37 -11
- package/dist/slices/library/transfer.js +2 -1
- package/dist/slices/library/used-by.js +25 -10
- package/dist/slices/loudness/loudnorm.js +51 -11
- package/dist/slices/model-checks/cost.js +61 -0
- package/dist/slices/model-checks/listing.js +124 -0
- package/dist/slices/model-checks/model.js +20 -0
- package/dist/slices/model-checks/record.js +32 -0
- package/dist/slices/model-checks/repo.js +120 -0
- package/dist/slices/model-checks/rules.js +112 -0
- package/dist/slices/model-checks/run.js +143 -0
- package/dist/slices/model-checks/service.js +198 -0
- package/dist/slices/model-upkeep/switch.js +70 -25
- package/dist/slices/model-upkeep/usage.js +26 -11
- package/dist/slices/narration/breaths.js +2 -1
- package/dist/slices/narration/clean-pieces.js +2 -1
- package/dist/slices/narration/concat.js +2 -1
- package/dist/slices/narration/peaks.js +3 -4
- package/dist/slices/narration/pronunciation-chunks.js +4 -3
- package/dist/slices/narration/pronunciation.js +3 -2
- package/dist/slices/narration/steering.js +4 -3
- package/dist/slices/notifications/notifier.js +4 -3
- package/dist/slices/notifications/rules.js +5 -2
- package/dist/slices/notifications/settings.js +4 -12
- package/dist/slices/notifications/subject.js +2 -1
- package/dist/slices/onboarding/copy.js +2 -1
- package/dist/slices/onboarding/first-run.js +3 -2
- package/dist/slices/onboarding/full-video.js +3 -2
- package/dist/slices/onboarding/install.js +4 -3
- package/dist/slices/onboarding/model.js +0 -16
- package/dist/slices/onboarding/packs.js +22 -22
- package/dist/slices/onboarding/quick-short.js +2 -1
- package/dist/slices/onboarding/sample.js +0 -1
- package/dist/slices/onboarding/state.js +2 -11
- package/dist/slices/onboarding/template.js +2 -1
- package/dist/slices/patch-notes/library.js +3 -2
- package/dist/slices/play-drafts/convert.js +4 -0
- package/dist/slices/play-drafts/review-inputs.js +8 -2
- package/dist/slices/play-drafts/review.js +5 -4
- package/dist/slices/play-drafts/schema.js +4 -0
- package/dist/slices/project-templates/from-project.js +9 -2
- package/dist/slices/project-templates/repo.js +6 -1
- package/dist/slices/project-templates/setup.js +8 -0
- package/dist/slices/project-templates/stand-ins.js +22 -0
- package/dist/slices/rebuild/activity.js +2 -0
- package/dist/slices/rebuild/admission-repo.js +3 -2
- package/dist/slices/rebuild/narration-history.js +4 -5
- package/dist/slices/rebuild/narration-retry.js +2 -1
- package/dist/slices/rebuild/preview-details.js +27 -9
- package/dist/slices/rebuild/preview-plan.js +3 -8
- package/dist/slices/rebuild/recipe-build.js +8 -3
- package/dist/slices/rebuild/recipe-describe.js +3 -3
- package/dist/slices/rebuild/recipe-digest.js +58 -0
- package/dist/slices/rebuild/recipe-input-schema.js +10 -0
- package/dist/slices/rebuild/recipe-keywords.js +71 -0
- package/dist/slices/rebuild/recipe-legacy.js +5 -1
- package/dist/slices/rebuild/recipe-model.js +4 -0
- package/dist/slices/rebuild/recipe-narration-text.js +2 -1
- package/dist/slices/rebuild/recipe-preparation.js +3 -3
- package/dist/slices/rebuild/recipe-reference.js +8 -4
- package/dist/slices/rebuild/recipe-reviews.js +27 -7
- package/dist/slices/rebuild/recipe-save.js +6 -3
- package/dist/slices/rebuild/recipe-scenes.js +40 -11
- package/dist/slices/rebuild/recipe-shorts.js +8 -8
- package/dist/slices/rebuild/recipe-social.js +46 -0
- package/dist/slices/rebuild/recipe-text.js +64 -20
- package/dist/slices/rebuild/recipe-validation.js +98 -28
- package/dist/slices/rebuild/recipe-visual.js +55 -16
- package/dist/slices/rebuild/recipe-work.js +15 -3
- package/dist/slices/rebuild/recipe-youtube.js +4 -3
- package/dist/slices/rebuild/recovery-selection.js +3 -1
- package/dist/slices/rebuild/recovery.js +3 -2
- package/dist/slices/rebuild/repo.js +4 -3
- package/dist/slices/rebuild/review-promise.js +25 -0
- package/dist/slices/rebuild/review-redo.js +2 -1
- package/dist/slices/rebuild/runtime-admission.js +4 -3
- package/dist/slices/rebuild/runtime-agent-review.js +11 -5
- package/dist/slices/rebuild/runtime-animate.js +9 -8
- package/dist/slices/rebuild/runtime-article.js +3 -2
- package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
- package/dist/slices/rebuild/runtime-document.js +8 -11
- package/dist/slices/rebuild/runtime-export-bed.js +6 -11
- package/dist/slices/rebuild/runtime-export-edit.js +6 -15
- package/dist/slices/rebuild/runtime-export-inputs.js +7 -7
- package/dist/slices/rebuild/runtime-export-short.js +8 -4
- package/dist/slices/rebuild/runtime-export.js +34 -12
- package/dist/slices/rebuild/runtime-figure-card.js +2 -1
- package/dist/slices/rebuild/runtime-image.js +4 -9
- package/dist/slices/rebuild/runtime-instructions.js +2 -0
- package/dist/slices/rebuild/runtime-keywords.js +59 -0
- package/dist/slices/rebuild/runtime-lines.js +2 -11
- package/dist/slices/rebuild/runtime-local.js +14 -20
- package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
- package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
- package/dist/slices/rebuild/runtime-narration-text.js +10 -15
- package/dist/slices/rebuild/runtime-pictures.js +2 -4
- package/dist/slices/rebuild/runtime-piece-label.js +10 -6
- package/dist/slices/rebuild/runtime-plan.js +31 -5
- package/dist/slices/rebuild/runtime-provider.js +60 -19
- package/dist/slices/rebuild/runtime-publication.js +10 -9
- package/dist/slices/rebuild/runtime-review.js +33 -28
- package/dist/slices/rebuild/runtime-run.js +4 -1
- package/dist/slices/rebuild/runtime-shorts.js +34 -50
- package/dist/slices/rebuild/runtime-store.js +3 -8
- package/dist/slices/rebuild/runtime-subtitles.js +16 -14
- package/dist/slices/rebuild/runtime-voices.js +8 -15
- package/dist/slices/rebuild/runtime-youtube.js +11 -29
- package/dist/slices/rebuild/transition-repo.js +6 -5
- package/dist/slices/rebuild/work-records.js +6 -0
- package/dist/slices/reruns/cascade.js +1 -2
- package/dist/slices/reruns/index.js +6 -9
- package/dist/slices/reviews/external-model.js +3 -0
- package/dist/slices/reviews/external-repo.js +2 -1
- package/dist/slices/reviews/external-rows.js +2 -3
- package/dist/slices/reviews/model.js +26 -8
- package/dist/slices/reviews/repo.js +2 -1
- package/dist/slices/reviews/rules.js +1 -0
- package/dist/slices/reviews/view.js +5 -2
- package/dist/slices/revisions/downloads.js +4 -5
- package/dist/slices/revisions/mutation-assets.js +7 -4
- package/dist/slices/revisions/mutation-cues.js +2 -5
- package/dist/slices/revisions/mutations.js +0 -1
- package/dist/slices/revisions/repo.js +3 -1
- package/dist/slices/revisions/schema.js +1 -0
- package/dist/slices/revisions/view.js +20 -0
- package/dist/slices/run-cost/limits.js +5 -2
- package/dist/slices/run-cost/meter.js +12 -5
- package/dist/slices/run-cost/panel.js +8 -74
- package/dist/slices/run-cost/plan-readings.js +127 -0
- package/dist/slices/run-cost/plan-use.js +169 -0
- package/dist/slices/run-cost/pricing.js +3 -3
- package/dist/slices/run-cost/week.js +32 -4
- package/dist/slices/schedules/agenda.js +11 -2
- package/dist/slices/schedules/by-date.js +42 -0
- package/dist/slices/schedules/calendar.js +5 -0
- package/dist/slices/schedules/design-agenda.js +36 -0
- package/dist/slices/schedules/design-check.js +41 -0
- package/dist/slices/schedules/design-run.js +126 -0
- package/dist/slices/schedules/next-run.js +62 -0
- package/dist/slices/schedules/prepare.js +18 -2
- package/dist/slices/schedules/repo.js +24 -16
- package/dist/slices/schedules/rescore.js +35 -0
- package/dist/slices/schedules/scheduler.js +13 -3
- package/dist/slices/schedules/schema.js +54 -3
- package/dist/slices/schedules/score.js +107 -0
- package/dist/slices/schedules/service.js +57 -24
- package/dist/slices/schedules/topic-list.js +15 -0
- package/dist/slices/schedules/topic-scores.js +104 -0
- package/dist/slices/schedules/topics.js +48 -36
- package/dist/slices/settings/cli-paths.js +4 -6
- package/dist/slices/settings/first-run.js +2 -11
- package/dist/slices/settings/model-reach.js +3 -17
- package/dist/slices/settings/model.js +10 -0
- package/dist/slices/settings/playback.js +33 -22
- package/dist/slices/settings/probe-read.js +16 -0
- package/dist/slices/settings/repo.js +33 -0
- package/dist/slices/settings/tutorial.js +2 -2
- package/dist/slices/settings/voices.js +4 -12
- package/dist/slices/shorts/pick.js +2 -15
- package/dist/slices/shorts/prompts.js +2 -13
- package/dist/slices/shorts/render.js +3 -0
- package/dist/slices/social/channel.js +44 -0
- package/dist/slices/social/defaults.js +17 -0
- package/dist/slices/social/due.js +36 -0
- package/dist/slices/social/extension.js +18 -0
- package/dist/slices/social/fit.js +115 -0
- package/dist/slices/social/limits.js +186 -0
- package/dist/slices/social/links.js +21 -0
- package/dist/slices/social/media.js +131 -0
- package/dist/slices/social/model.js +75 -0
- package/dist/slices/social/notice.js +19 -0
- package/dist/slices/social/pack.js +176 -0
- package/dist/slices/social/post-prompt.js +55 -0
- package/dist/slices/social/queue.js +31 -0
- package/dist/slices/social/repo.js +133 -0
- package/dist/slices/social/reshape.js +97 -0
- package/dist/slices/social/rules.js +5 -0
- package/dist/slices/social/schema.js +70 -0
- package/dist/slices/social/serve.js +51 -0
- package/dist/slices/social/service.js +128 -0
- package/dist/slices/social/settings.js +21 -0
- package/dist/slices/social/sources.js +114 -0
- package/dist/slices/social/state.js +110 -0
- package/dist/slices/social/text.js +149 -0
- package/dist/slices/storage/arrange.js +3 -1
- package/dist/slices/storage/assets.js +8 -10
- package/dist/slices/storage/backup-designs.js +74 -0
- package/dist/slices/storage/backup-export.js +8 -3
- package/dist/slices/storage/backup-format.js +10 -0
- package/dist/slices/storage/backup-import.js +20 -2
- package/dist/slices/storage/delete-project.js +6 -5
- package/dist/slices/storage/files-location.js +6 -8
- package/dist/slices/storage/layout.js +13 -2
- package/dist/slices/storage/model.js +3 -0
- package/dist/slices/storage/portable.js +16 -11
- package/dist/slices/storage/schema.js +2 -0
- package/dist/slices/storage/staging-refs.js +2 -1
- package/dist/slices/storage/staging.js +6 -9
- package/dist/slices/storage/trim.js +10 -3
- package/dist/slices/studio/calendar.js +4 -1
- package/dist/slices/studio/pick.js +2 -11
- package/dist/slices/studio/plan.js +6 -15
- package/dist/slices/studio/queue.js +3 -14
- package/dist/slices/studio/releases.js +26 -0
- package/dist/slices/studio/settings.js +14 -51
- package/dist/slices/studio/videos.js +12 -0
- package/dist/slices/style-preview/render.js +34 -13
- package/dist/slices/style-preview/schema.js +13 -0
- package/dist/slices/style-preview/service.js +2 -1
- package/dist/slices/style-preview/settings.js +33 -5
- package/dist/slices/telemetry/collector-client.js +2 -4
- package/dist/slices/telemetry/flush.js +2 -4
- package/dist/slices/telemetry/model.js +0 -7
- package/dist/slices/telemetry/record.js +10 -3
- package/dist/slices/template-studio/anatomy-view.js +118 -0
- package/dist/slices/template-studio/anatomy.js +73 -0
- package/dist/slices/template-studio/bakeoff-make.js +225 -0
- package/dist/slices/template-studio/bakeoff-repo.js +83 -0
- package/dist/slices/template-studio/bakeoff.js +333 -0
- package/dist/slices/template-studio/budget.js +103 -0
- package/dist/slices/template-studio/checks.js +273 -0
- package/dist/slices/template-studio/document-sample.js +56 -0
- package/dist/slices/template-studio/edit.js +15 -0
- package/dist/slices/template-studio/for-all.js +161 -0
- package/dist/slices/template-studio/free-video.js +31 -0
- package/dist/slices/template-studio/free.js +176 -0
- package/dist/slices/template-studio/gate.js +40 -0
- package/dist/slices/template-studio/hidden.js +20 -0
- package/dist/slices/template-studio/jobs.js +79 -0
- package/dist/slices/template-studio/loudness.js +111 -0
- package/dist/slices/template-studio/make.js +40 -0
- package/dist/slices/template-studio/model.js +54 -0
- package/dist/slices/template-studio/pack-import.js +253 -0
- package/dist/slices/template-studio/pack-samples.js +60 -0
- package/dist/slices/template-studio/pack.js +205 -0
- package/dist/slices/template-studio/paid-view.js +66 -0
- package/dist/slices/template-studio/paid.js +348 -0
- package/dist/slices/template-studio/quote.js +148 -0
- package/dist/slices/template-studio/ready.js +104 -0
- package/dist/slices/template-studio/repo.js +134 -0
- package/dist/slices/template-studio/reviews-path.js +58 -0
- package/dist/slices/template-studio/runner.js +84 -0
- package/dist/slices/template-studio/save.js +236 -0
- package/dist/slices/template-studio/say-it-as.js +248 -0
- package/dist/slices/template-studio/schedule-gate.js +34 -0
- package/dist/slices/template-studio/schedule-price.js +30 -0
- package/dist/slices/template-studio/schedule-sample.js +87 -0
- package/dist/slices/template-studio/schema.js +218 -0
- package/dist/slices/template-studio/scope.js +124 -0
- package/dist/slices/template-studio/sections.js +176 -0
- package/dist/slices/template-studio/service.js +173 -0
- package/dist/slices/template-studio/status.js +174 -0
- package/dist/slices/template-studio/topic.js +223 -0
- package/dist/slices/trash/designs.js +76 -0
- package/dist/slices/trash/model.js +13 -4
- package/dist/slices/trash/service.js +52 -2
- package/dist/slices/tutorials/library.js +3 -2
- package/dist/slices/video/ass-text.js +17 -0
- package/dist/slices/video/audio-export.js +2 -64
- package/dist/slices/video/encoding.js +160 -0
- package/dist/slices/video/ffmpeg.js +23 -21
- package/dist/slices/video/figure-card.js +1 -15
- package/dist/slices/video/slideshow.js +43 -18
- package/dist/slices/voices/palette.js +0 -3
- package/dist/slices/youtube/answer.js +2 -15
- package/dist/slices/youtube/edits-repo.js +2 -11
- package/dist/tutorials/Agents-MCP.md +2 -1
- package/dist/tutorials/Assistant.md +42 -0
- package/dist/tutorials/Channels.md +2 -0
- package/dist/tutorials/Home-and-Projects.md +19 -0
- package/dist/tutorials/Install.md +1 -0
- package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
- package/dist/tutorials/Models.md +33 -1
- package/dist/tutorials/Notifications.md +6 -0
- package/dist/tutorials/Play-Images.md +4 -0
- package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
- package/dist/tutorials/Prompts.md +10 -6
- package/dist/tutorials/Remote-Access.md +63 -0
- package/dist/tutorials/Reviews-and-Checkpoints.md +13 -2
- package/dist/tutorials/Schedules.md +21 -1
- package/dist/tutorials/Settings-Reference.md +50 -8
- package/dist/tutorials/Template-Studio.md +125 -0
- package/dist/tutorials/Templates.md +3 -0
- package/dist/tutorials/_Sidebar.md +5 -0
- package/dist/updater/work-in-progress.js +42 -12
- package/dist/web/assets/index-CkAI_2E7.css +1 -0
- package/dist/web/assets/index-DcD0cdfo.js +334 -0
- package/dist/web/assets/{pdf-T7MCwjIv.js → pdf-TODRwF31.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +5 -1
- package/dist/slices/article/provided-entries.js +0 -66
- package/dist/slices/article/run.js +0 -145
- package/dist/slices/images/run.js +0 -234
- package/dist/slices/narration/legacy-plan.js +0 -58
- package/dist/slices/narration/run.js +0 -270
- package/dist/slices/rebuild/runtime-actions.js +0 -90
- package/dist/slices/research/run.js +0 -224
- package/dist/slices/subtitles/prepare.js +0 -194
- package/dist/slices/subtitles/transcript.js +0 -34
- package/dist/slices/thumbnail/run.js +0 -219
- package/dist/slices/video/audio-inputs.js +0 -33
- package/dist/slices/video/reuse-audio.js +0 -62
- package/dist/slices/video/run.js +0 -78
- package/dist/slices/video/write-export.js +0 -158
- package/dist/slices/video/write-subtitles.js +0 -59
- package/dist/web/assets/index-BadsoORk.css +0 -1
- package/dist/web/assets/index-D8LqNsCl.js +0 -326
|
@@ -1,11 +1,12 @@
|
|
|
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,
|
|
5
|
-
import {
|
|
4
|
+
import { httpFailure, noImage, quoted, refusedImage, unreadable } from "../explain.js";
|
|
5
|
+
import { failureText, httpProviderError, kindOfStatus, requireKey, safeJson, } from "../http-failure.js";
|
|
6
|
+
import { modelAccessOf } from "../model-access.js";
|
|
6
7
|
import { describeBytes, sniffImage } from "./bytes.js";
|
|
7
8
|
import { discoverGoogleImages } from "./models.js";
|
|
8
|
-
import {
|
|
9
|
+
import { attachedPictures, promptFor } from "./reference.js";
|
|
9
10
|
// The HTTP gateway adapter for Google's own image generation, billed to a Gemini API key
|
|
10
11
|
// rather than to a host reselling the same models. Like the OpenAI one it hands back the
|
|
11
12
|
// bytes with the call, so there is no link to follow.
|
|
@@ -65,15 +66,15 @@ export function googleImage(deps) {
|
|
|
65
66
|
model: req.model,
|
|
66
67
|
// With an establishing image the input is two parts, the image first; the Gemini
|
|
67
68
|
// image models draw with an input image as their reference.
|
|
68
|
-
input:
|
|
69
|
+
input: attachedPictures(req).length === 0
|
|
69
70
|
? req.prompt
|
|
70
71
|
: [
|
|
71
|
-
...
|
|
72
|
+
...attachedPictures(req).map(({ image }) => ({
|
|
72
73
|
type: "image",
|
|
73
74
|
mime_type: image.mime,
|
|
74
75
|
data: Buffer.from(image.bytes).toString("base64"),
|
|
75
76
|
})),
|
|
76
|
-
{ type: "text", text:
|
|
77
|
+
{ type: "text", text: promptFor(req.prompt, req) },
|
|
77
78
|
],
|
|
78
79
|
// The stage sends Number as that many independent calls, one piece each, so one
|
|
79
80
|
// image per request is what it asks for. Nothing about style is set: the stage
|
|
@@ -123,12 +124,7 @@ function decode(part) {
|
|
|
123
124
|
return { bytes, mime };
|
|
124
125
|
}
|
|
125
126
|
function keyOf(deps) {
|
|
126
|
-
|
|
127
|
-
const key = deps.key();
|
|
128
|
-
if (key === undefined || key === "") {
|
|
129
|
-
throw providerError({ kind: "missing_key", message: missingKey("Google") });
|
|
130
|
-
}
|
|
131
|
-
return key;
|
|
127
|
+
return requireKey(deps.key(), "Google");
|
|
132
128
|
}
|
|
133
129
|
// Only the adapter sees the vendor's status code, so only the adapter names the kind.
|
|
134
130
|
function kindOf(status, named, message) {
|
|
@@ -141,27 +137,16 @@ function kindOf(status, named, message) {
|
|
|
141
137
|
if (status === 400 && refusalWords.test(message)) {
|
|
142
138
|
return "refusal";
|
|
143
139
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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";
|
|
140
|
+
// Interactions wraps quota failures in a string-coded error and exposes the limit
|
|
141
|
+
// in the message. Zero allocated capacity cannot be fixed by waiting and retrying.
|
|
142
|
+
if (status === 429 &&
|
|
143
|
+
/quota exceeded for metric:[^\r\n]*?\blimit:\s*0\s*(?:,|$)/im.test(message)) {
|
|
144
|
+
return "unsupported";
|
|
154
145
|
}
|
|
155
|
-
|
|
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";
|
|
146
|
+
return kindOfStatus(status);
|
|
162
147
|
}
|
|
163
148
|
async function failure(response) {
|
|
164
|
-
const text = await response
|
|
149
|
+
const text = await failureText(response);
|
|
165
150
|
const parsed = errorBody.safeParse(safeJson(text));
|
|
166
151
|
// The provider's own words, through the redactor - an error body may quote the key back.
|
|
167
152
|
const named = parsed.success ? parsed.data.error.status : undefined;
|
|
@@ -170,24 +155,23 @@ async function failure(response) {
|
|
|
170
155
|
const delay = parsed.success
|
|
171
156
|
? parsed.data.error.details?.find((one) => one["@type"] === "type.googleapis.com/google.rpc.RetryInfo")?.retryDelay
|
|
172
157
|
: undefined;
|
|
173
|
-
const retryAfterMs = retryAfter(response.headers.get("retry-after")) ?? googleRetryDelay(delay, message);
|
|
174
158
|
const detail = message || response.statusText;
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
:
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
});
|
|
159
|
+
const refused = kind === "refusal" && refusalWords.test(message);
|
|
160
|
+
return httpProviderError(response, kind, kind === "unsupported"
|
|
161
|
+
? `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.`
|
|
162
|
+
: // PERMISSION_DENIED and FAILED_PRECONDITION also cover keys without access, billing
|
|
163
|
+
// and region limits, so they read as a content refusal only when Google says so.
|
|
164
|
+
refused
|
|
165
|
+
? refusedImage("Google", detail)
|
|
166
|
+
: httpFailure({
|
|
167
|
+
provider: "Google",
|
|
168
|
+
status: response.status,
|
|
169
|
+
detail,
|
|
170
|
+
subject: "image request",
|
|
171
|
+
}), googleRetryDelay(delay, message),
|
|
172
|
+
// A key that reads the model list but is denied or told "not found" here is denied the
|
|
173
|
+
// model the request names: Google answers a bad key with 400 API_KEY_INVALID.
|
|
174
|
+
refused ? undefined : modelAccessOf(response.status, `${named ?? ""} ${message}`, true));
|
|
191
175
|
}
|
|
192
176
|
function googleRetryDelay(delay, message) {
|
|
193
177
|
const seconds = delay?.match(/^(\d+(?:\.\d+)?)s$/)?.[1] ??
|
|
@@ -207,11 +191,3 @@ function parse(text) {
|
|
|
207
191
|
}
|
|
208
192
|
return parsed.data;
|
|
209
193
|
}
|
|
210
|
-
function safeJson(text) {
|
|
211
|
-
try {
|
|
212
|
-
return JSON.parse(text);
|
|
213
|
-
}
|
|
214
|
-
catch {
|
|
215
|
-
return undefined;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
@@ -1,11 +1,12 @@
|
|
|
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,
|
|
5
|
-
import {
|
|
4
|
+
import { httpFailure, noImage, refusedImage, unreadable } from "../explain.js";
|
|
5
|
+
import { failureText, httpProviderError, kindOfStatus, requireKey, safeJson, } from "../http-failure.js";
|
|
6
|
+
import { modelAccessOf } from "../model-access.js";
|
|
6
7
|
import { describeBytes, sniffImage } from "./bytes.js";
|
|
7
8
|
import { discoverOpenAiImages } from "./models.js";
|
|
8
|
-
import {
|
|
9
|
+
import { attachedPictures, promptFor } from "./reference.js";
|
|
9
10
|
// The HTTP gateway adapter for OpenAI's images endpoint: the platform's own `fetch` and
|
|
10
11
|
// nothing else, because the whole call is one request. Unlike fal and Replicate this one
|
|
11
12
|
// hands back the image itself - a GPT image model always answers with base64, never a URL -
|
|
@@ -56,7 +57,7 @@ export function openAiImage(deps) {
|
|
|
56
57
|
id: "openai-image",
|
|
57
58
|
models: () => discoverOpenAiImages(deps),
|
|
58
59
|
generate: async (req) => {
|
|
59
|
-
const pictures =
|
|
60
|
+
const pictures = attachedPictures(req);
|
|
60
61
|
const response = pictures.length === 0
|
|
61
62
|
? await deps.fetch(`${openAiImagesBase}/images/generations`, {
|
|
62
63
|
method: "POST",
|
|
@@ -96,11 +97,11 @@ export function openAiImage(deps) {
|
|
|
96
97
|
};
|
|
97
98
|
}
|
|
98
99
|
// The edits endpoint takes several input images as repeated `image[]` parts: the establishing
|
|
99
|
-
// image first, then the cast pictures.
|
|
100
|
+
// image (or, for a design's edit, the picture to change) first, then the cast pictures.
|
|
100
101
|
function editForm(req, pictures) {
|
|
101
102
|
const form = new FormData();
|
|
102
103
|
form.set("model", req.model);
|
|
103
|
-
form.set("prompt",
|
|
104
|
+
form.set("prompt", promptFor(req.prompt, req));
|
|
104
105
|
form.set("n", "1");
|
|
105
106
|
form.set("size", sizeFor(req.model, req.aspect));
|
|
106
107
|
for (const [index, { image }] of pictures.entries())
|
|
@@ -122,51 +123,31 @@ function decode(b64) {
|
|
|
122
123
|
return { bytes, mime };
|
|
123
124
|
}
|
|
124
125
|
function keyOf(deps) {
|
|
125
|
-
|
|
126
|
-
const key = deps.key();
|
|
127
|
-
if (key === undefined || key === "") {
|
|
128
|
-
throw providerError({ kind: "missing_key", message: missingKey("OpenAI") });
|
|
129
|
-
}
|
|
130
|
-
return key;
|
|
126
|
+
return requireKey(deps.key(), "OpenAI");
|
|
131
127
|
}
|
|
132
128
|
// Only the adapter sees the vendor's status code, so only the adapter names the kind.
|
|
133
129
|
function kindOf(status, code) {
|
|
134
130
|
if (code !== undefined && code !== null && refusalCodes.includes(code)) {
|
|
135
131
|
return "refusal";
|
|
136
132
|
}
|
|
137
|
-
|
|
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";
|
|
133
|
+
return kindOfStatus(status);
|
|
150
134
|
}
|
|
151
135
|
async function failure(response) {
|
|
152
|
-
const text = await response
|
|
136
|
+
const text = await failureText(response);
|
|
153
137
|
const parsed = errorBody.safeParse(safeJson(text));
|
|
154
138
|
// The provider's own words, through the redactor - an error body may quote the key back.
|
|
155
139
|
const message = redact(parsed.success ? parsed.data.error.message : text.trim() || response.statusText);
|
|
156
|
-
const retryAfterMs = retryAfter(response.headers.get("retry-after"));
|
|
157
140
|
const kind = kindOf(response.status, parsed.success ? parsed.data.error.code : undefined);
|
|
158
|
-
return
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
...(retryAfterMs === undefined ? {} : { retryAfterMs }),
|
|
169
|
-
});
|
|
141
|
+
return httpProviderError(response, kind, kind === "refusal"
|
|
142
|
+
? refusedImage("OpenAI", message)
|
|
143
|
+
: httpFailure({
|
|
144
|
+
provider: "OpenAI",
|
|
145
|
+
status: response.status,
|
|
146
|
+
detail: message,
|
|
147
|
+
subject: "image request",
|
|
148
|
+
}), undefined, kind === "refusal"
|
|
149
|
+
? undefined
|
|
150
|
+
: modelAccessOf(response.status, `${parsed.success ? (parsed.data.error.code ?? "") : ""} ${message}`));
|
|
170
151
|
}
|
|
171
152
|
function parse(text) {
|
|
172
153
|
const parsed = generated.safeParse(safeJson(text));
|
|
@@ -178,11 +159,3 @@ function parse(text) {
|
|
|
178
159
|
}
|
|
179
160
|
return parsed.data;
|
|
180
161
|
}
|
|
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,9 @@
|
|
|
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,
|
|
5
|
-
import {
|
|
4
|
+
import { httpFailure, noImage, providerSaid, refusedImage, unreadable } from "../explain.js";
|
|
5
|
+
import { failureText, httpProviderError, kindOfStatus, requireKey, safeJson, } from "../http-failure.js";
|
|
6
|
+
import { modelAccessOf } from "../model-access.js";
|
|
6
7
|
import { downloadImage } from "./bytes.js";
|
|
7
8
|
import { withReferences } from "./reference.js";
|
|
8
9
|
import { dataUri, downloadVideo } from "./video.js";
|
|
@@ -37,6 +38,7 @@ const errorBody = z.object({ detail: z.string().optional(), title: z.string().op
|
|
|
37
38
|
// `canceled` cannot happen here - nothing cancels a prediction this app made - but reading
|
|
38
39
|
// it as terminal beats polling forever.
|
|
39
40
|
const settled = ["succeeded", "failed", "canceled"];
|
|
41
|
+
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
42
|
export function replicateImage(deps) {
|
|
41
43
|
return {
|
|
42
44
|
id: "replicate",
|
|
@@ -44,6 +46,8 @@ export function replicateImage(deps) {
|
|
|
44
46
|
generate: async (req) => {
|
|
45
47
|
// The Replicate models listed take no input image to draw from (the FLUX image inputs
|
|
46
48
|
// copy the picture's composition), so an establishing image is refused, not dropped.
|
|
49
|
+
if (req.edit !== undefined)
|
|
50
|
+
throw providerError({ kind: "unsupported", message: replicateEditRefusal });
|
|
47
51
|
if (req.reference !== undefined)
|
|
48
52
|
throw providerError({
|
|
49
53
|
kind: "unsupported",
|
|
@@ -70,7 +74,7 @@ export function replicateImage(deps) {
|
|
|
70
74
|
}),
|
|
71
75
|
});
|
|
72
76
|
if (!response.ok) {
|
|
73
|
-
throw await failure(response);
|
|
77
|
+
throw await failure(response, "image request", true);
|
|
74
78
|
}
|
|
75
79
|
const url = await settle(deps, parse(await response.text()), req.signal);
|
|
76
80
|
// The download rides inside the attempt: a link that 404s is a failed attempt.
|
|
@@ -100,7 +104,7 @@ export function replicateImage(deps) {
|
|
|
100
104
|
}),
|
|
101
105
|
});
|
|
102
106
|
if (!response.ok)
|
|
103
|
-
throw await failure(response, "video clip request");
|
|
107
|
+
throw await failure(response, "video clip request", true);
|
|
104
108
|
const url = await settle(deps, parse(await response.text()), req.signal);
|
|
105
109
|
return await downloadVideo({
|
|
106
110
|
fetch: deps.fetch,
|
|
@@ -172,46 +176,21 @@ function declined(current) {
|
|
|
172
176
|
});
|
|
173
177
|
}
|
|
174
178
|
function auth(deps) {
|
|
175
|
-
|
|
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}` };
|
|
179
|
+
return { Authorization: `Bearer ${requireKey(deps.key(), "Replicate")}` };
|
|
181
180
|
}
|
|
182
|
-
//
|
|
183
|
-
function
|
|
184
|
-
|
|
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(() => "");
|
|
181
|
+
// `atModel`: the request went to the model's own address, so a 404 or 403 is about the model.
|
|
182
|
+
async function failure(response, subject = "image request", atModel = false) {
|
|
183
|
+
const text = await failureText(response);
|
|
200
184
|
const parsed = errorBody.safeParse(safeJson(text));
|
|
201
185
|
// The provider's own words, through the redactor - an error body may quote the key back.
|
|
202
186
|
const detail = parsed.success ? (parsed.data.detail ?? parsed.data.title) : undefined;
|
|
203
187
|
const message = redact(detail ?? text.trim());
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
detail: message || response.statusText,
|
|
211
|
-
subject,
|
|
212
|
-
}),
|
|
213
|
-
...(retryAfterMs === undefined ? {} : { retryAfterMs }),
|
|
214
|
-
});
|
|
188
|
+
return httpProviderError(response, kindOfStatus(response.status), httpFailure({
|
|
189
|
+
provider: "Replicate",
|
|
190
|
+
status: response.status,
|
|
191
|
+
detail: message || response.statusText,
|
|
192
|
+
subject,
|
|
193
|
+
}), undefined, modelAccessOf(response.status, text, atModel));
|
|
215
194
|
}
|
|
216
195
|
function parse(text) {
|
|
217
196
|
const parsed = prediction.safeParse(safeJson(text));
|
|
@@ -223,11 +202,3 @@ function parse(text) {
|
|
|
223
202
|
}
|
|
224
203
|
return parsed.data;
|
|
225
204
|
}
|
|
226
|
-
function safeJson(text) {
|
|
227
|
-
try {
|
|
228
|
-
return JSON.parse(text);
|
|
229
|
-
}
|
|
230
|
-
catch {
|
|
231
|
-
return undefined;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// Public search interest without a key: Google's search suggestions (DuckDuckGo's when Google
|
|
3
|
+
// doesn't answer) and the Wikipedia article's views last month. Checked keyless on 2026-10-18;
|
|
4
|
+
// Google Trends answers 429/404 to such calls, so it isn't asked.
|
|
5
|
+
// ceiling: one service that hangs costs a topic this long at most.
|
|
6
|
+
export const interestRequestMs = 4000;
|
|
7
|
+
const suggestAnswer = z.tuple([z.string(), z.array(z.string())]).rest(z.unknown());
|
|
8
|
+
const openSearchAnswer = z.tuple([z.string(), z.array(z.string())]).rest(z.unknown());
|
|
9
|
+
const pageviewsAnswer = z.object({ items: z.array(z.object({ views: z.number() }).loose()) });
|
|
10
|
+
class Unanswered extends Error {
|
|
11
|
+
reason;
|
|
12
|
+
constructor(reason) {
|
|
13
|
+
super(reason);
|
|
14
|
+
this.reason = reason;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// "en" from "en-GB"; a language Wikipedia names by its two letters.
|
|
18
|
+
function languageOf(language) {
|
|
19
|
+
const code = language.trim().toLowerCase().slice(0, 2);
|
|
20
|
+
return /^[a-z]{2}$/.test(code) ? code : "en";
|
|
21
|
+
}
|
|
22
|
+
// The last whole month before `now`, as the pageviews API names its days.
|
|
23
|
+
export function lastMonth(now) {
|
|
24
|
+
const first = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - 1, 1));
|
|
25
|
+
const last = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 0));
|
|
26
|
+
const day = (date) => `${String(date.getUTCFullYear())}${String(date.getUTCMonth() + 1).padStart(2, "0")}${String(date.getUTCDate()).padStart(2, "0")}00`;
|
|
27
|
+
return { start: day(first), end: day(last) };
|
|
28
|
+
}
|
|
29
|
+
export function createSearchInterest(deps) {
|
|
30
|
+
const headers = {
|
|
31
|
+
"User-Agent": `Slopify/${deps.version} (https://github.com/gentbajko/slopify)`,
|
|
32
|
+
Accept: "application/json",
|
|
33
|
+
};
|
|
34
|
+
const json = async (url, signal) => {
|
|
35
|
+
const timeout = AbortSignal.timeout(interestRequestMs);
|
|
36
|
+
let response;
|
|
37
|
+
try {
|
|
38
|
+
response = await deps.fetch(url, { headers, signal: AbortSignal.any([signal, timeout]) });
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
throw new Unanswered(timeout.aborted ? "timeout" : "offline");
|
|
42
|
+
}
|
|
43
|
+
if (!response.ok)
|
|
44
|
+
throw new Unanswered("refused");
|
|
45
|
+
try {
|
|
46
|
+
return await response.json();
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
throw new Unanswered("refused");
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const reasonOf = (error) => error instanceof Unanswered ? error.reason : "offline";
|
|
53
|
+
const suggestions = async (topic, language, signal) => {
|
|
54
|
+
const q = encodeURIComponent(topic);
|
|
55
|
+
let failure = "offline";
|
|
56
|
+
for (const url of [
|
|
57
|
+
`https://suggestqueries.google.com/complete/search?client=firefox&hl=${language}&q=${q}`,
|
|
58
|
+
`https://duckduckgo.com/ac/?q=${q}&type=list&kl=wt-wt`,
|
|
59
|
+
]) {
|
|
60
|
+
try {
|
|
61
|
+
const parsed = suggestAnswer.safeParse(await json(url, signal));
|
|
62
|
+
if (parsed.success)
|
|
63
|
+
return parsed.data[1].slice(0, 10);
|
|
64
|
+
failure = "refused";
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
failure = reasonOf(error);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return failure;
|
|
71
|
+
};
|
|
72
|
+
const wikiViews = async (topic, language, signal) => {
|
|
73
|
+
try {
|
|
74
|
+
const found = openSearchAnswer.safeParse(await json(`https://${language}.wikipedia.org/w/api.php?action=opensearch&format=json&namespace=0&limit=1&search=${encodeURIComponent(topic)}`, signal));
|
|
75
|
+
if (!found.success)
|
|
76
|
+
return "refused";
|
|
77
|
+
const title = found.data[1][0];
|
|
78
|
+
if (title === undefined)
|
|
79
|
+
return null;
|
|
80
|
+
const { start, end } = lastMonth(deps.now());
|
|
81
|
+
let answer;
|
|
82
|
+
try {
|
|
83
|
+
answer = await json(`https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/${language}.wikipedia/all-access/user/${encodeURIComponent(title.replaceAll(" ", "_"))}/monthly/${start}/${end}`, signal);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
// An article too new to have a month of views answers 404.
|
|
87
|
+
if (reasonOf(error) === "refused")
|
|
88
|
+
return null;
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
const views = pageviewsAnswer.safeParse(answer);
|
|
92
|
+
return views.success ? views.data.items.reduce((sum, item) => sum + item.views, 0) : null;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
return reasonOf(error);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
return async (topic, rawLanguage, signal) => {
|
|
99
|
+
const language = languageOf(rawLanguage);
|
|
100
|
+
const [offered, views] = await Promise.all([
|
|
101
|
+
suggestions(topic, language, signal),
|
|
102
|
+
wikiViews(topic, language, signal),
|
|
103
|
+
]);
|
|
104
|
+
const failed = (value) => typeof value === "string";
|
|
105
|
+
if (failed(offered) && failed(views))
|
|
106
|
+
return { ok: false, reason: offered };
|
|
107
|
+
return {
|
|
108
|
+
ok: true,
|
|
109
|
+
suggestions: failed(offered) ? null : offered,
|
|
110
|
+
wikiViews: failed(views) ? null : views,
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { safeJson } from "./http-failure.js";
|
|
1
2
|
import { cartesiaVersion } from "./tts/cartesia.js";
|
|
2
3
|
// Settings → Providers' Test button, per provider. Some answer a key they do not recognise
|
|
3
4
|
// with something other than 401: Google with 400 API_KEY_INVALID, ElevenLabs with 400
|
|
@@ -21,6 +22,37 @@ function listed(ids) {
|
|
|
21
22
|
};
|
|
22
23
|
}
|
|
23
24
|
const field = (value, key) => typeof value === "object" && value !== null ? value[key] : undefined;
|
|
25
|
+
function idsOf(rows, key, strip) {
|
|
26
|
+
if (!Array.isArray(rows))
|
|
27
|
+
return undefined;
|
|
28
|
+
return rows.flatMap((row) => {
|
|
29
|
+
const id = field(row, key);
|
|
30
|
+
return typeof id === "string" && id !== "" ? [strip ? id.replace(strip, "") : id] : [];
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
// `{ data: [{ id }] }`: OpenAI's and OpenRouter's lists.
|
|
34
|
+
function dataList(url) {
|
|
35
|
+
return {
|
|
36
|
+
url: () => url,
|
|
37
|
+
read: (body) => {
|
|
38
|
+
const ids = idsOf(field(safeJson(body), "data"), "id");
|
|
39
|
+
return ids === undefined ? undefined : { ids };
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const googleBase = "https://generativelanguage.googleapis.com/v1beta/models?pageSize=1000";
|
|
44
|
+
const googleList = {
|
|
45
|
+
url: (page) => page === undefined ? googleBase : `${googleBase}&pageToken=${encodeURIComponent(page)}`,
|
|
46
|
+
read: (body) => {
|
|
47
|
+
const value = safeJson(body);
|
|
48
|
+
const ids = idsOf(field(value, "models"), "name", /^models\//);
|
|
49
|
+
if (ids === undefined)
|
|
50
|
+
return undefined;
|
|
51
|
+
const next = field(value, "nextPageToken");
|
|
52
|
+
return typeof next === "string" && next !== "" ? { ids, next } : { ids };
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
const openAiList = dataList("https://api.openai.com/v1/models");
|
|
24
56
|
const google = {
|
|
25
57
|
url: "https://generativelanguage.googleapis.com/v1beta/models?pageSize=1",
|
|
26
58
|
headers: (key) => ({ "x-goog-api-key": key }),
|
|
@@ -28,6 +60,7 @@ const google = {
|
|
|
28
60
|
model: {
|
|
29
61
|
url: (model) => `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(model.replace(/^models\//, ""))}`,
|
|
30
62
|
},
|
|
63
|
+
list: googleList,
|
|
31
64
|
};
|
|
32
65
|
export const keyProbes = {
|
|
33
66
|
openrouter: {
|
|
@@ -40,9 +73,20 @@ export const keyProbes = {
|
|
|
40
73
|
return Array.isArray(data) ? data.map((one) => field(one, "id")) : [];
|
|
41
74
|
}),
|
|
42
75
|
},
|
|
76
|
+
list: dataList("https://openrouter.ai/api/v1/models"),
|
|
77
|
+
},
|
|
78
|
+
"openai-tts": {
|
|
79
|
+
url: "https://api.openai.com/v1/models",
|
|
80
|
+
headers: bearer,
|
|
81
|
+
model: openAiModel,
|
|
82
|
+
list: openAiList,
|
|
83
|
+
},
|
|
84
|
+
"openai-image": {
|
|
85
|
+
url: "https://api.openai.com/v1/models",
|
|
86
|
+
headers: bearer,
|
|
87
|
+
model: openAiModel,
|
|
88
|
+
list: openAiList,
|
|
43
89
|
},
|
|
44
|
-
"openai-tts": { url: "https://api.openai.com/v1/models", headers: bearer, model: openAiModel },
|
|
45
|
-
"openai-image": { url: "https://api.openai.com/v1/models", headers: bearer, model: openAiModel },
|
|
46
90
|
"google-image": google,
|
|
47
91
|
"google-tts": google,
|
|
48
92
|
// fal.ai's model list answers without a key; its price lookup requires one.
|
|
@@ -72,6 +116,13 @@ export const keyProbes = {
|
|
|
72
116
|
url: () => "https://api.elevenlabs.io/v1/models",
|
|
73
117
|
lists: listed((body) => Array.isArray(body) ? body.map((one) => field(one, "model_id")) : []),
|
|
74
118
|
},
|
|
119
|
+
list: {
|
|
120
|
+
url: () => "https://api.elevenlabs.io/v1/models",
|
|
121
|
+
read: (body) => {
|
|
122
|
+
const ids = idsOf(safeJson(body), "model_id");
|
|
123
|
+
return ids === undefined ? undefined : { ids };
|
|
124
|
+
},
|
|
125
|
+
},
|
|
75
126
|
},
|
|
76
127
|
cartesia: {
|
|
77
128
|
url: "https://api.cartesia.ai/voices?limit=1",
|
|
@@ -6,6 +6,7 @@ import { redact } from "../../kernel/log.js";
|
|
|
6
6
|
import { documentMessages } from "../../kernel/ports/llm-documents.js";
|
|
7
7
|
import { providerError } from "../../kernel/ports/model.js";
|
|
8
8
|
import { cliCheck, cliName, cliReported, commandOf } from "../explain.js";
|
|
9
|
+
import { accessField } from "../model-access.js";
|
|
9
10
|
import { nodeAntigravityModels } from "./antigravity-models.js";
|
|
10
11
|
import { imageWorkspace, readFileName, unseenImages } from "./image-workspace.js";
|
|
11
12
|
import { cliInput, cliShaped, deliveredInput, endedWithout, promptOf, stopCliRun, stuckCli, } from "./run-cli.js";
|
|
@@ -205,6 +206,8 @@ function failure(binary, model, message, sentence, now = Date.now) {
|
|
|
205
206
|
if (/invalid model selection/i.test(message))
|
|
206
207
|
return providerError({
|
|
207
208
|
kind: "unsupported",
|
|
209
|
+
// agy lists models a plan can't run and refuses them with this sentence.
|
|
210
|
+
access: "no-access",
|
|
208
211
|
message: `The ${cliName(binary)} does not offer the model "${model}". Run "agy models" in a terminal to see the ones it has, pick one in the Edit tab (Edit project → Providers), then use Continue the run.`,
|
|
209
212
|
});
|
|
210
213
|
if (/quota|resource.?exhausted|capacity/i.test(message) &&
|
|
@@ -233,6 +236,7 @@ function failure(binary, model, message, sentence, now = Date.now) {
|
|
|
233
236
|
}
|
|
234
237
|
return providerError({
|
|
235
238
|
kind: "other",
|
|
239
|
+
...accessField(null, message),
|
|
236
240
|
message: sentence ?? cliReported(binary, redact(message), cliCheck(binary)),
|
|
237
241
|
});
|
|
238
242
|
}
|