@gentbajko/slopify 2.5.0 → 3.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/LICENSE +201 -21
- package/NOTICE +12 -0
- package/README.md +21 -40
- package/SUBTITLES.md +1 -1
- package/dist/adapter-registry.js +3 -0
- package/dist/adapters/alignment/cache.js +4 -1
- package/dist/adapters/alignment/ctc.js +25 -23
- package/dist/adapters/alignment/index.js +37 -6
- package/dist/adapters/alignment/multilingual.js +267 -0
- package/dist/adapters/alignment/protocol.js +11 -0
- package/dist/adapters/alignment/quality.js +4 -3
- package/dist/adapters/alignment/sentences.js +95 -0
- package/dist/adapters/alignment/spec.js +24 -0
- package/dist/adapters/alignment/spell.js +769 -0
- package/dist/adapters/alignment/text.js +56 -9
- package/dist/adapters/alignment/window.js +34 -30
- package/dist/adapters/alignment/worker.js +23 -21
- package/dist/adapters/explain.js +11 -11
- package/dist/adapters/host-cli/index.js +44 -5
- package/dist/adapters/host-cli/transport.js +7 -5
- package/dist/adapters/image/bytes.js +2 -2
- package/dist/adapters/image/codex-output.js +1 -1
- package/dist/adapters/image/codex.js +87 -22
- package/dist/adapters/image/fal.js +13 -5
- package/dist/adapters/image/google.js +11 -8
- package/dist/adapters/image/openai.js +14 -7
- package/dist/adapters/image/reference.js +34 -0
- package/dist/adapters/image/replicate.js +7 -2
- package/dist/adapters/image/video.js +2 -2
- package/dist/adapters/key-probes.js +36 -0
- package/dist/adapters/llm/claude-code.js +168 -32
- package/dist/adapters/llm/cli-login-error.js +1 -1
- package/dist/adapters/llm/codex-limits.js +157 -0
- package/dist/adapters/llm/codex.js +99 -12
- package/dist/adapters/llm/document-workspace.js +2 -2
- package/dist/adapters/llm/gemini-workspace.js +1 -1
- package/dist/adapters/llm/gemini.js +16 -3
- package/dist/adapters/llm/image-workspace.js +58 -0
- package/dist/adapters/llm/openrouter.js +11 -3
- package/dist/adapters/llm/run-cli.js +12 -7
- package/dist/adapters/tts/cartesia.js +10 -0
- package/dist/adapters/tts/elevenlabs.js +31 -9
- package/dist/adapters/tts/inworld-async.js +9 -5
- package/dist/adapters/tts/inworld.js +17 -3
- package/dist/adapters/tts/openai.js +3 -0
- package/dist/adapters/tts/voice-languages.js +80 -0
- package/dist/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansArabic-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansDevanagari-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansHebrew-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansThai-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/OFL.txt +93 -0
- package/dist/assets/fonts/noto/SOURCE.txt +18 -0
- package/dist/assets/sample/sample-audiobook.tar +0 -0
- package/dist/assets/sample/sample-podcast.tar +0 -0
- package/dist/assets/sample/sample-project.tar +0 -0
- package/dist/catalog/merge.js +132 -0
- package/dist/catalog/registry.js +13 -13
- package/dist/catalog/schema.js +2 -0
- package/dist/catalog/store.js +147 -8
- package/dist/compose.yaml +71 -0
- package/dist/edge/autostart/docker-record.js +32 -0
- package/dist/edge/autostart/docker.js +50 -0
- package/dist/edge/autostart/index.js +78 -0
- package/dist/edge/autostart/launcher.js +176 -0
- package/dist/edge/autostart/model.js +3 -0
- package/dist/edge/autostart/native.js +210 -0
- package/dist/edge/autostart/prompt.js +66 -0
- package/dist/edge/autostart/service.js +81 -0
- package/dist/edge/cli.js +57 -51
- package/dist/edge/docker-install/activation.js +56 -0
- package/dist/edge/docker-install/apply.js +458 -0
- package/dist/edge/docker-install/engine.js +362 -0
- package/dist/edge/docker-install/run.js +154 -0
- package/dist/edge/docker-install/state.js +146 -0
- package/dist/edge/{docker-projects → docker-install}/volume.js +1 -5
- package/dist/edge/docker.js +14 -22
- package/dist/edge/host-cli.js +1 -1
- package/dist/edge/http/actions.js +32 -10
- package/dist/edge/http/app.js +58 -2
- package/dist/edge/http/auditions.js +70 -0
- package/dist/edge/http/autostart.js +37 -0
- package/dist/edge/http/channel-memory.js +92 -0
- package/dist/edge/http/channels.js +128 -0
- package/dist/edge/http/entries.js +22 -3
- package/dist/edge/http/files.js +1 -1
- package/dist/edge/http/folder-location.js +1 -1
- package/dist/edge/http/home.js +39 -0
- package/dist/edge/http/host-cli.js +29 -5
- package/dist/edge/http/narration-peaks.js +76 -0
- package/dist/edge/http/onboarding.js +152 -0
- package/dist/edge/http/open-folder.js +1 -1
- package/dist/edge/http/patch-notes.js +45 -0
- package/dist/edge/http/planning.js +4 -2
- package/dist/edge/http/project-create.js +87 -0
- package/dist/edge/http/projects.js +31 -99
- package/dist/edge/http/prompts.js +40 -3
- package/dist/edge/http/pronunciations.js +23 -4
- package/dist/edge/http/providers.js +86 -0
- package/dist/edge/http/reviews.js +121 -0
- package/dist/edge/http/revision-files.js +1 -1
- package/dist/edge/http/revisions.js +1 -1
- package/dist/edge/http/run-cost.js +25 -0
- package/dist/edge/http/schedules.js +111 -6
- package/dist/edge/http/settings.js +84 -6
- package/dist/edge/http/storage-files.js +50 -0
- package/dist/edge/http/storage.js +29 -2
- package/dist/edge/http/studio.js +207 -0
- package/dist/edge/http/style-preview.js +100 -0
- package/dist/edge/http/subtitles.js +1 -1
- package/dist/edge/http/trash.js +69 -0
- package/dist/edge/http/update.js +24 -3
- package/dist/edge/http/whats-new.js +15 -0
- package/dist/edge/http/youtube-edits.js +83 -0
- package/dist/edge/native-update.js +62 -0
- package/dist/host-cli/open-folder.js +10 -10
- package/dist/host-cli/runtime.js +9 -1
- package/dist/kernel/db/migrations/0025-automatic-reviews.sql +40 -0
- package/dist/kernel/db/migrations/0026-schedule-topic-generation.sql +23 -0
- package/dist/kernel/db/migrations/0027-run-cost.sql +58 -0
- package/dist/kernel/db/migrations/0030-automatic-retries.sql +18 -0
- package/dist/kernel/db/migrations/0031-prompt-history-and-description-edits.sql +33 -0
- package/dist/kernel/db/migrations/0032-channels.sql +65 -0
- package/dist/kernel/db/migrations/0034-script-prompts.sql +23 -0
- package/dist/kernel/db/migrations/0035-narration-aliases.sql +13 -0
- package/dist/kernel/db/migrations/0037-project-uploads.sql +8 -0
- package/dist/kernel/db/migrations/0038-voice-languages.sql +7 -0
- package/dist/kernel/db/migrations/0039-channel-essentials.sql +64 -0
- package/dist/kernel/db/migrations/0040-standalone-usage.sql +35 -0
- package/dist/kernel/paths.js +27 -6
- package/dist/kernel/pipeline.js +4 -1
- package/dist/kernel/ports/host-cli.js +122 -14
- package/dist/kernel/ports/key-probe.js +1 -0
- package/dist/kernel/ports/languages.js +157 -0
- package/dist/kernel/ports/model.js +5 -2
- package/dist/kernel/ports/narration-aliases.js +60 -0
- package/dist/kernel/ports/plan-limits.js +36 -0
- package/dist/kernel/runner/attempt.js +17 -8
- package/dist/kernel/runner/audition.js +36 -0
- package/dist/kernel/runner/graph.js +24 -5
- package/dist/kernel/runner/index.js +35 -5
- package/dist/kernel/runner/meter.js +1 -0
- package/dist/kernel/runner/providers.js +142 -7
- package/dist/kernel/runner/retry-policy.js +43 -0
- package/dist/kernel/runner/standalone.js +134 -0
- package/dist/kernel/runner/work-authority.js +28 -2
- package/dist/main.js +272 -16
- package/dist/patch-notes/0.4.2-to-1.0.md +93 -0
- package/dist/patch-notes/1.0-to-2.0.md +74 -0
- package/dist/patch-notes/2.0-to-3.0.md +257 -0
- package/dist/patch-notes/3.0.0.md +70 -0
- package/dist/patch-notes/index.json +26 -0
- package/dist/slices/admission/model.js +27 -0
- package/dist/slices/admission/repo.js +24 -4
- package/dist/slices/admission/rules.js +79 -1
- package/dist/slices/admission/schema.js +58 -1
- package/dist/slices/admission/short-mode.js +47 -0
- package/dist/slices/admission/start.js +41 -5
- package/dist/slices/article/continuation.js +2 -2
- package/dist/slices/article/provided-entries.js +2 -2
- package/dist/slices/article/run.js +6 -2
- package/dist/slices/article/segments.js +3 -3
- package/dist/slices/backups/folder.js +14 -6
- package/dist/slices/batch/index.js +7 -2
- package/dist/slices/cancel/index.js +1 -1
- package/dist/slices/channels/cast-images.js +110 -0
- package/dist/slices/channels/cast-match.js +32 -0
- package/dist/slices/channels/images.js +19 -0
- package/dist/slices/channels/model.js +5 -0
- package/dist/slices/channels/rebrand.js +100 -0
- package/dist/slices/channels/repo.js +218 -0
- package/dist/slices/channels/runs.js +129 -0
- package/dist/slices/channels/schema.js +129 -0
- package/dist/slices/channels/service.js +180 -0
- package/dist/slices/channels/studio-csv.js +110 -0
- package/dist/slices/channels/videos.js +120 -0
- package/dist/slices/checkpoints/recovery.js +10 -0
- package/dist/slices/control/index.js +2 -1
- package/dist/slices/document/fonts.js +1 -1
- package/dist/slices/document/render.js +1 -1
- package/dist/slices/episodes/related.js +90 -0
- package/dist/slices/episodes/repo.js +60 -0
- package/dist/slices/episodes/service.js +58 -0
- package/dist/slices/episodes/summarize.js +170 -0
- package/dist/slices/estimate/index.js +109 -28
- package/dist/slices/estimate/requests.js +60 -2
- package/dist/slices/fixes/rules.js +73 -0
- package/dist/slices/fonts/coverage.js +82 -0
- package/dist/slices/fonts/sfnt.js +74 -0
- package/dist/slices/images/run.js +8 -5
- package/dist/slices/images/scale.js +84 -0
- package/dist/slices/library/diff.js +122 -0
- package/dist/slices/library/history.js +100 -0
- package/dist/slices/library/model.js +3 -0
- package/dist/slices/library/photorealistic.js +49 -0
- package/dist/slices/library/repo.js +19 -14
- package/dist/slices/library/save.js +62 -12
- package/dist/slices/library/slots.js +7 -1
- package/dist/slices/library/used-by.js +153 -0
- package/dist/slices/loudness/level-pieces.js +41 -0
- package/dist/slices/loudness/loudnorm.js +164 -0
- package/dist/slices/loudness/model.js +153 -0
- package/dist/slices/model-upkeep/model.js +10 -0
- package/dist/slices/model-upkeep/switch.js +217 -0
- package/dist/slices/model-upkeep/usage.js +183 -0
- package/dist/slices/narration/aliases-library.js +31 -0
- package/dist/slices/narration/aliases-schema.js +53 -0
- package/dist/slices/narration/aliases.js +49 -0
- package/dist/slices/narration/blocks.js +352 -0
- package/dist/slices/narration/chunk.js +19 -7
- package/dist/slices/narration/concat.js +2 -2
- package/dist/slices/narration/describe.js +45 -0
- package/dist/slices/narration/pauses-model.js +63 -0
- package/dist/slices/narration/pauses.js +269 -0
- package/dist/slices/narration/peaks-model.js +1 -0
- package/dist/slices/narration/peaks.js +94 -0
- package/dist/slices/narration/preparation.js +21 -3
- package/dist/slices/narration/pronunciation-chunks.js +3 -3
- package/dist/slices/narration/pronunciation.js +72 -25
- package/dist/slices/narration/run.js +6 -6
- package/dist/slices/narration/shared-glossary.js +1 -1
- package/dist/slices/narration/steering.js +15 -4
- package/dist/slices/notifications/notifier.js +21 -3
- package/dist/slices/notifications/rules.js +22 -1
- package/dist/slices/onboarding/copy.js +143 -0
- package/dist/slices/onboarding/first-run.js +46 -0
- package/dist/slices/onboarding/install.js +119 -0
- package/dist/slices/onboarding/model.js +64 -0
- package/dist/slices/onboarding/packs.js +491 -0
- package/dist/slices/onboarding/quick-short.js +129 -0
- package/dist/slices/onboarding/sample.js +132 -0
- package/dist/slices/onboarding/state.js +68 -0
- package/dist/slices/onboarding/template.js +73 -0
- package/dist/slices/patch-notes/library.js +73 -0
- package/dist/slices/patch-notes/seen.js +77 -0
- package/dist/slices/play-drafts/convert.js +125 -6
- package/dist/slices/play-drafts/readiness.js +3 -0
- package/dist/slices/play-drafts/repo.js +2 -0
- package/dist/slices/play-drafts/review-inputs.js +20 -3
- package/dist/slices/play-drafts/schema.js +89 -0
- package/dist/slices/play-drafts/service.js +4 -1
- package/dist/slices/play-drafts/start.js +43 -18
- package/dist/slices/project-templates/from-project.js +50 -4
- package/dist/slices/project-templates/one-off.js +26 -0
- package/dist/slices/project-templates/repo.js +2 -1
- package/dist/slices/project-templates/service.js +15 -4
- package/dist/slices/project-templates/setup.js +18 -2
- package/dist/slices/rebuild/admission-repo.js +1 -1
- package/dist/slices/rebuild/model.js +6 -0
- package/dist/slices/rebuild/preview-details.js +46 -3
- package/dist/slices/rebuild/preview-plan.js +13 -6
- package/dist/slices/rebuild/recipe-audio-parts.js +40 -7
- package/dist/slices/rebuild/recipe-audio.js +66 -12
- package/dist/slices/rebuild/recipe-build.js +8 -4
- package/dist/slices/rebuild/recipe-cast.js +18 -0
- package/dist/slices/rebuild/recipe-checkpoints.js +11 -9
- package/dist/slices/rebuild/recipe-describe.js +93 -0
- package/dist/slices/rebuild/recipe-edit.js +13 -1
- package/dist/slices/rebuild/recipe-exports.js +62 -8
- package/dist/slices/rebuild/recipe-input-schema.js +35 -0
- package/dist/slices/rebuild/recipe-legacy.js +9 -0
- package/dist/slices/rebuild/recipe-loudness.js +45 -0
- package/dist/slices/rebuild/recipe-model.js +25 -6
- package/dist/slices/rebuild/recipe-pauses.js +7 -0
- package/dist/slices/rebuild/recipe-preparation.js +3 -3
- package/dist/slices/rebuild/recipe-provider-choice.js +11 -1
- package/dist/slices/rebuild/recipe-reference.js +15 -1
- package/dist/slices/rebuild/recipe-reviews.js +117 -0
- package/dist/slices/rebuild/recipe-save.js +4 -1
- package/dist/slices/rebuild/recipe-shorts.js +23 -3
- package/dist/slices/rebuild/recipe-text.js +114 -19
- package/dist/slices/rebuild/recipe-validation.js +14 -2
- package/dist/slices/rebuild/recipe-visual.js +96 -33
- package/dist/slices/rebuild/recipe-voices.js +286 -0
- package/dist/slices/rebuild/recipe-work.js +77 -6
- package/dist/slices/rebuild/recipe-youtube.js +2 -0
- package/dist/slices/rebuild/recovery-conflict.js +7 -3
- package/dist/slices/rebuild/recovery-model.js +3 -0
- package/dist/slices/rebuild/recovery-selection.js +28 -2
- package/dist/slices/rebuild/recovery.js +35 -17
- package/dist/slices/rebuild/repo.js +3 -3
- package/dist/slices/rebuild/retry.js +18 -0
- package/dist/slices/rebuild/review-redo.js +110 -0
- package/dist/slices/rebuild/runtime-actions.js +5 -0
- package/dist/slices/rebuild/runtime-admission.js +4 -1
- package/dist/slices/rebuild/runtime-animate.js +4 -4
- package/dist/slices/rebuild/runtime-article.js +5 -5
- package/dist/slices/rebuild/runtime-document.js +4 -4
- package/dist/slices/rebuild/runtime-export-bed.js +43 -0
- package/dist/slices/rebuild/runtime-export-edit.js +70 -11
- package/dist/slices/rebuild/runtime-export-inputs.js +52 -10
- package/dist/slices/rebuild/runtime-export-short.js +85 -0
- package/dist/slices/rebuild/runtime-export.js +84 -19
- package/dist/slices/rebuild/runtime-figure-card.js +87 -0
- package/dist/slices/rebuild/runtime-image.js +21 -2
- package/dist/slices/rebuild/runtime-local.js +148 -24
- package/dist/slices/rebuild/runtime-materialize.js +8 -0
- package/dist/slices/rebuild/runtime-narration-reuse.js +2 -1
- package/dist/slices/rebuild/runtime-narration-text.js +7 -7
- package/dist/slices/rebuild/runtime-pictures.js +28 -0
- package/dist/slices/rebuild/runtime-piece-label.js +27 -0
- package/dist/slices/rebuild/runtime-provider.js +126 -18
- package/dist/slices/rebuild/runtime-publication.js +21 -5
- package/dist/slices/rebuild/runtime-review.js +237 -0
- package/dist/slices/rebuild/runtime-run.js +17 -11
- package/dist/slices/rebuild/runtime-shorts.js +44 -17
- package/dist/slices/rebuild/runtime-store.js +39 -10
- package/dist/slices/rebuild/runtime-subtitles.js +72 -19
- package/dist/slices/rebuild/runtime-voices.js +103 -0
- package/dist/slices/rebuild/runtime-youtube.js +7 -6
- package/dist/slices/rebuild/soften.js +49 -0
- package/dist/slices/rebuild/transition-repo.js +9 -2
- package/dist/slices/research/run.js +4 -4
- package/dist/slices/research/synthesis.js +2 -2
- package/dist/slices/reviews/model.js +105 -0
- package/dist/slices/reviews/outcome.js +22 -0
- package/dist/slices/reviews/repo.js +106 -0
- package/dist/slices/reviews/rules.js +63 -0
- package/dist/slices/reviews/verdict.js +71 -0
- package/dist/slices/reviews/view.js +30 -0
- package/dist/slices/revisions/adopt-content.js +5 -2
- package/dist/slices/revisions/adopt.js +3 -1
- package/dist/slices/revisions/downloads.js +7 -1
- package/dist/slices/revisions/image-plan.js +183 -0
- package/dist/slices/revisions/mutation-assets.js +10 -0
- package/dist/slices/revisions/mutation-cues.js +71 -0
- package/dist/slices/revisions/mutation-request.js +2 -1
- package/dist/slices/revisions/mutations.js +97 -3
- package/dist/slices/revisions/schema.js +11 -1
- package/dist/slices/run-cost/limits.js +128 -0
- package/dist/slices/run-cost/meter.js +47 -0
- package/dist/slices/run-cost/panel.js +234 -0
- package/dist/slices/run-cost/pricing.js +92 -0
- package/dist/slices/run-cost/week.js +108 -0
- package/dist/slices/schedules/agenda.js +158 -0
- package/dist/slices/schedules/repo.js +58 -18
- package/dist/slices/schedules/scheduler.js +67 -16
- package/dist/slices/schedules/schema.js +138 -1
- package/dist/slices/schedules/service.js +43 -4
- package/dist/slices/schedules/similar.js +90 -0
- package/dist/slices/schedules/topic-list.js +163 -0
- package/dist/slices/schedules/topics.js +422 -0
- package/dist/slices/settings/first-run.js +102 -0
- package/dist/slices/settings/health.js +190 -0
- package/dist/slices/settings/key-guides.js +128 -0
- package/dist/slices/settings/key-test.js +85 -0
- package/dist/slices/settings/model.js +6 -1
- package/dist/slices/settings/playback.js +15 -0
- package/dist/slices/settings/repo.js +17 -3
- package/dist/slices/settings/voices.js +64 -4
- package/dist/slices/settings/whats-new.js +64 -0
- package/dist/slices/shorts/captions.js +9 -0
- package/dist/slices/shorts/pick.js +3 -3
- package/dist/slices/shorts/prompts.js +1 -1
- package/dist/slices/shorts/render.js +54 -5
- package/dist/slices/storage/asset-name.js +3 -0
- package/dist/slices/storage/backup-export.js +48 -9
- package/dist/slices/storage/backup-format.js +38 -1
- package/dist/slices/storage/backup-import.js +191 -19
- package/dist/slices/storage/delete-project.js +7 -4
- package/dist/slices/storage/documents.js +79 -0
- package/dist/slices/storage/files-location.js +531 -0
- package/dist/slices/storage/layout.js +14 -4
- package/dist/slices/storage/model.js +11 -0
- package/dist/slices/storage/portable.js +92 -12
- package/dist/slices/storage/reconcile.js +14 -1
- package/dist/slices/storage/repo.js +4 -1
- package/dist/slices/storage/schema.js +11 -0
- package/dist/slices/storage/trim.js +146 -0
- package/dist/slices/studio/disclosure.js +74 -0
- package/dist/slices/studio/model.js +28 -0
- package/dist/slices/studio/pack.js +209 -0
- package/dist/slices/studio/settings.js +133 -0
- package/dist/slices/style-preview/images.js +61 -0
- package/dist/slices/style-preview/render.js +161 -0
- package/dist/slices/style-preview/schema.js +45 -0
- package/dist/slices/style-preview/service.js +93 -0
- package/dist/slices/style-preview/settings.js +89 -0
- package/dist/slices/subtitles/captions.js +42 -9
- package/dist/slices/subtitles/model.js +22 -0
- package/dist/slices/subtitles/prepare.js +27 -16
- package/dist/slices/subtitles/transcript.js +1 -1
- package/dist/slices/thumbnail/run.js +7 -7
- package/dist/slices/trash/model.js +25 -0
- package/dist/slices/trash/service.js +273 -0
- package/dist/slices/uploads/repo.js +20 -0
- package/dist/slices/video/ambient-bed-schema.js +15 -0
- package/dist/slices/video/ambient-bed.js +95 -0
- package/dist/slices/video/ambient-mix.js +72 -0
- package/dist/slices/video/audio-inputs.js +2 -2
- package/dist/slices/video/cards.js +5 -2
- package/dist/slices/video/edit-list.js +23 -2
- package/dist/slices/video/edit-settings.js +13 -3
- package/dist/slices/video/ffmpeg.js +63 -9
- package/dist/slices/video/figure-card.js +492 -0
- package/dist/slices/video/figure-spans.js +51 -0
- package/dist/slices/video/plan.js +125 -13
- package/dist/slices/video/run.js +14 -12
- package/dist/slices/video/slideshow.js +39 -4
- package/dist/slices/voices/attribution.js +69 -0
- package/dist/slices/voices/audio-files.js +82 -0
- package/dist/slices/voices/audition.js +25 -0
- package/dist/slices/voices/cast.js +56 -0
- package/dist/slices/voices/grouping.js +49 -0
- package/dist/slices/voices/join.js +35 -0
- package/dist/slices/voices/languages.js +25 -0
- package/dist/slices/voices/model.js +179 -0
- package/dist/slices/voices/palette.js +26 -0
- package/dist/slices/voices/panel.js +91 -0
- package/dist/slices/voices/portraits.js +55 -0
- package/dist/slices/voices/script.js +136 -0
- package/dist/slices/voices/timing.js +58 -0
- package/dist/slices/youtube/answer.js +1 -1
- package/dist/slices/youtube/chapters.js +126 -0
- package/dist/slices/youtube/edits-repo.js +69 -0
- package/dist/slices/youtube/edits.js +89 -0
- package/dist/slices/youtube/placeholders.js +98 -0
- package/dist/slices/youtube/transcript.js +11 -4
- package/dist/updater/service.js +66 -21
- package/dist/web/assets/index-CUA2sUxU.css +1 -0
- package/dist/web/assets/index-CX590kE-.js +303 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/dist/web/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/dist/web/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/dist/web/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/dist/web/assets/{pdf-BLF2i8c2.js → pdf-BG8n_uc5.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +4 -4
- package/dist/edge/docker-launch.js +0 -81
- package/dist/edge/docker-projects/activation.js +0 -35
- package/dist/edge/docker-projects/claims.js +0 -85
- package/dist/edge/docker-projects/committed.js +0 -40
- package/dist/edge/docker-projects/engine.js +0 -461
- package/dist/edge/docker-projects/install.js +0 -254
- package/dist/edge/docker-projects/prune.js +0 -66
- package/dist/edge/docker-projects/recover.js +0 -100
- package/dist/edge/docker-projects/state.js +0 -225
- package/dist/web/assets/index-CktpxlJd.js +0 -171
- package/dist/web/assets/index-DB-vOnGU.css +0 -1
- package/scripts/docker-run.sh +0 -3
- /package/dist/edge/{docker-projects → docker-install}/tree.js +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { providerError } from "../ports/model.js";
|
|
2
|
+
import { isProviderError, providerError } from "../ports/model.js";
|
|
3
|
+
import { planAccountOf } from "../ports/plan-limits.js";
|
|
3
4
|
import { attempt } from "./attempt.js";
|
|
4
5
|
export function stageProviders(deps, context, pieceId) {
|
|
5
6
|
const ctx = {
|
|
@@ -15,7 +16,44 @@ export function stageProviders(deps, context, pieceId) {
|
|
|
15
16
|
...(pieceId === undefined ? {} : { pieceId }),
|
|
16
17
|
signal: context.signal,
|
|
17
18
|
};
|
|
18
|
-
const
|
|
19
|
+
const queued = (provider, work) => deps.queue ? deps.queue.run(provider, context.signal, work) : work();
|
|
20
|
+
const waiter = { projectId: context.stage.projectId, stage: context.stage.kind };
|
|
21
|
+
// A CLI whose plan allowance is used up is waited for here, outside the queue, so the wait
|
|
22
|
+
// holds no provider slot; the call is then made afresh with a full set of attempts.
|
|
23
|
+
const schedule = async (provider, work) => {
|
|
24
|
+
const account = planAccountOf(provider);
|
|
25
|
+
const gate = deps.limits;
|
|
26
|
+
if (account === undefined || gate === undefined)
|
|
27
|
+
return queued(provider, work);
|
|
28
|
+
for (;;) {
|
|
29
|
+
await gate.ready(account, waiter, context.signal);
|
|
30
|
+
try {
|
|
31
|
+
return await queued(provider, work);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const hit = isProviderError(error) ? error.fault.planLimit : undefined;
|
|
35
|
+
if (hit === undefined || context.signal.aborted)
|
|
36
|
+
throw error;
|
|
37
|
+
gate.exhausted(hit);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
// Metering never fails a call: the answer is already paid for.
|
|
42
|
+
const meter = (call) => {
|
|
43
|
+
if (deps.meter === undefined)
|
|
44
|
+
return;
|
|
45
|
+
try {
|
|
46
|
+
deps.meter.record({ ...call, projectId: context.stage.projectId, stage: context.stage.kind });
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
deps.log.write("warn", "usage.record", {
|
|
50
|
+
projectId: context.stage.projectId,
|
|
51
|
+
stage: context.stage.kind,
|
|
52
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const since = (started) => Math.max(0, deps.clock.now().getTime() - started);
|
|
19
57
|
return {
|
|
20
58
|
llm: (call, onEvent) => {
|
|
21
59
|
// Resolved once; the adapter reads the stored key per request, so a key replaced
|
|
@@ -32,11 +70,17 @@ export function stageProviders(deps, context, pieceId) {
|
|
|
32
70
|
text,
|
|
33
71
|
...(reset === undefined ? {} : { reset }),
|
|
34
72
|
});
|
|
35
|
-
|
|
73
|
+
const started = deps.clock.now().getTime();
|
|
74
|
+
let limits;
|
|
75
|
+
const answered = schedule(call.provider, () => attempt(ctx, async (signal, progress) => {
|
|
36
76
|
preview("", true);
|
|
37
77
|
let text = "";
|
|
78
|
+
// Typed-ahead text the panel shows past the committed answer; the next delta
|
|
79
|
+
// replaces it, so the panel never shows a sentence twice.
|
|
80
|
+
let typed = false;
|
|
38
81
|
let usage = null;
|
|
39
82
|
let finishReason = null;
|
|
83
|
+
limits = undefined;
|
|
40
84
|
for await (const event of port.complete({
|
|
41
85
|
model: call.model,
|
|
42
86
|
...(call.thinkingConfig === undefined ? {} : { thinkingConfig: call.thinkingConfig }),
|
|
@@ -44,6 +88,7 @@ export function stageProviders(deps, context, pieceId) {
|
|
|
44
88
|
messages: call.messages,
|
|
45
89
|
...(call.documents === undefined ? {} : { documents: call.documents }),
|
|
46
90
|
...(call.webSearch === undefined ? {} : { webSearch: call.webSearch }),
|
|
91
|
+
...(call.images === undefined ? {} : { images: call.images }),
|
|
47
92
|
signal,
|
|
48
93
|
})) {
|
|
49
94
|
signal.throwIfAborted();
|
|
@@ -51,13 +96,22 @@ export function stageProviders(deps, context, pieceId) {
|
|
|
51
96
|
progress();
|
|
52
97
|
if (event.type === "delta") {
|
|
53
98
|
text += event.text;
|
|
99
|
+
if (typed)
|
|
100
|
+
preview(text, true);
|
|
101
|
+
else
|
|
102
|
+
preview(event.text);
|
|
103
|
+
typed = false;
|
|
104
|
+
}
|
|
105
|
+
else if (event.type === "partial") {
|
|
106
|
+
typed = true;
|
|
54
107
|
preview(event.text);
|
|
55
108
|
}
|
|
56
109
|
else if (event.type === "done") {
|
|
57
110
|
usage = event.usage;
|
|
58
111
|
finishReason = event.finishReason;
|
|
112
|
+
limits = event.limits;
|
|
59
113
|
}
|
|
60
|
-
if (event.type
|
|
114
|
+
if (event.type === "delta" || event.type === "done")
|
|
61
115
|
onEvent?.(event);
|
|
62
116
|
}
|
|
63
117
|
const answer = { text, usage, finishReason };
|
|
@@ -68,6 +122,28 @@ export function stageProviders(deps, context, pieceId) {
|
|
|
68
122
|
}
|
|
69
123
|
return answer;
|
|
70
124
|
}, { kind: "llm", streaming: port.capabilities.streams }));
|
|
125
|
+
return answered.then((result) => {
|
|
126
|
+
if (result.ok) {
|
|
127
|
+
const usage = result.value.usage;
|
|
128
|
+
meter({
|
|
129
|
+
kind: "llm",
|
|
130
|
+
provider: call.provider,
|
|
131
|
+
model: usage?.model ?? call.model,
|
|
132
|
+
...(usage === null
|
|
133
|
+
? {}
|
|
134
|
+
: {
|
|
135
|
+
tokensIn: usage.inputTokens,
|
|
136
|
+
tokensOut: usage.outputTokens,
|
|
137
|
+
...(usage.cachedInputTokens === undefined
|
|
138
|
+
? {}
|
|
139
|
+
: { cachedTokens: usage.cachedInputTokens }),
|
|
140
|
+
}),
|
|
141
|
+
wallMs: since(started),
|
|
142
|
+
...(limits === undefined ? {} : { limits }),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
});
|
|
71
147
|
},
|
|
72
148
|
tts: (call, observe) => {
|
|
73
149
|
const port = deps.registry.tts(call.provider);
|
|
@@ -95,13 +171,20 @@ export function stageProviders(deps, context, pieceId) {
|
|
|
95
171
|
});
|
|
96
172
|
}
|
|
97
173
|
};
|
|
98
|
-
|
|
174
|
+
const started = deps.clock.now().getTime();
|
|
175
|
+
const spoken = schedule(call.provider, () => attempt({ ...ctx, continuation }, async (signal, progress) => {
|
|
99
176
|
notify({ type: "start" });
|
|
100
177
|
try {
|
|
178
|
+
if (call.dialogue !== undefined && port.capabilities.dialogue !== true)
|
|
179
|
+
throw providerError({
|
|
180
|
+
kind: "unsupported",
|
|
181
|
+
message: `${call.provider} can't speak several voices in one request. Turn off Native multi-speaker under Speakers (Play → Audio, or Edit project → Providers), then Try again.`,
|
|
182
|
+
});
|
|
101
183
|
const spoken = await port.synthesize({
|
|
102
184
|
model: call.model,
|
|
103
185
|
voiceId: call.voiceId,
|
|
104
186
|
text: call.text,
|
|
187
|
+
...(call.dialogue === undefined ? {} : { dialogue: call.dialogue }),
|
|
105
188
|
signal,
|
|
106
189
|
onActivity: progress,
|
|
107
190
|
continuation,
|
|
@@ -138,6 +221,18 @@ export function stageProviders(deps, context, pieceId) {
|
|
|
138
221
|
throw error;
|
|
139
222
|
}
|
|
140
223
|
}, { kind: "tts", streaming: port.capabilities.streams }));
|
|
224
|
+
return spoken.then((result) => {
|
|
225
|
+
// Narration is billed by the characters sent, which is the text of this call.
|
|
226
|
+
if (result.ok)
|
|
227
|
+
meter({
|
|
228
|
+
kind: "tts",
|
|
229
|
+
provider: call.provider,
|
|
230
|
+
model: call.model ?? "",
|
|
231
|
+
characters: call.text.length,
|
|
232
|
+
wallMs: since(started),
|
|
233
|
+
});
|
|
234
|
+
return result;
|
|
235
|
+
});
|
|
141
236
|
},
|
|
142
237
|
image: (call) => {
|
|
143
238
|
const port = deps.registry.image(call.provider);
|
|
@@ -154,12 +249,14 @@ export function stageProviders(deps, context, pieceId) {
|
|
|
154
249
|
text,
|
|
155
250
|
reset: true,
|
|
156
251
|
});
|
|
157
|
-
|
|
252
|
+
const started = deps.clock.now().getTime();
|
|
253
|
+
const drawn = schedule(call.provider, () => attempt(ctx, (signal) => port.generate({
|
|
158
254
|
model: call.model,
|
|
159
255
|
prompt: call.prompt,
|
|
160
256
|
aspect: call.aspect,
|
|
161
257
|
...(call.thinking === undefined ? {} : { thinking: call.thinking }),
|
|
162
258
|
...(call.reference === undefined ? {} : { reference: call.reference }),
|
|
259
|
+
...(call.cast === undefined ? {} : { cast: call.cast }),
|
|
163
260
|
onProgress,
|
|
164
261
|
signal,
|
|
165
262
|
}),
|
|
@@ -169,6 +266,31 @@ export function stageProviders(deps, context, pieceId) {
|
|
|
169
266
|
kind: "image",
|
|
170
267
|
...(port.timeoutMs === undefined ? {} : { timeoutMs: port.timeoutMs }),
|
|
171
268
|
}));
|
|
269
|
+
return drawn.then((result) => {
|
|
270
|
+
if (result.ok) {
|
|
271
|
+
const { usage, limits } = result.value;
|
|
272
|
+
meter({
|
|
273
|
+
kind: "image",
|
|
274
|
+
provider: call.provider,
|
|
275
|
+
model: call.model,
|
|
276
|
+
images: 1,
|
|
277
|
+
size: call.aspect,
|
|
278
|
+
...(call.thinking === undefined ? {} : { quality: call.thinking }),
|
|
279
|
+
...(usage === undefined
|
|
280
|
+
? {}
|
|
281
|
+
: {
|
|
282
|
+
tokensIn: usage.inputTokens,
|
|
283
|
+
tokensOut: usage.outputTokens,
|
|
284
|
+
...(usage.cachedInputTokens === undefined
|
|
285
|
+
? {}
|
|
286
|
+
: { cachedTokens: usage.cachedInputTokens }),
|
|
287
|
+
}),
|
|
288
|
+
wallMs: since(started),
|
|
289
|
+
...(limits === undefined ? {} : { limits }),
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
return result;
|
|
293
|
+
});
|
|
172
294
|
},
|
|
173
295
|
animate: (call) => {
|
|
174
296
|
const port = deps.registry.image(call.provider);
|
|
@@ -178,7 +300,8 @@ export function stageProviders(deps, context, pieceId) {
|
|
|
178
300
|
kind: "unsupported",
|
|
179
301
|
message: `${call.provider} can't turn images into video clips. Choose fal.ai or Replicate as the image provider in Edit project → Providers, or turn Animate images off in Edit project → Inputs → Look.`,
|
|
180
302
|
}));
|
|
181
|
-
|
|
303
|
+
const started = deps.clock.now().getTime();
|
|
304
|
+
const animated = schedule(call.provider, () => attempt(ctx, (signal) => animate({
|
|
182
305
|
model: call.model,
|
|
183
306
|
prompt: call.prompt,
|
|
184
307
|
image: call.image,
|
|
@@ -188,6 +311,18 @@ export function stageProviders(deps, context, pieceId) {
|
|
|
188
311
|
}),
|
|
189
312
|
// Queued and slow: the 900 s runs over the whole call, polling included.
|
|
190
313
|
{ kind: "video" }));
|
|
314
|
+
return animated.then((result) => {
|
|
315
|
+
if (result.ok)
|
|
316
|
+
meter({
|
|
317
|
+
kind: "video",
|
|
318
|
+
provider: call.provider,
|
|
319
|
+
model: call.model,
|
|
320
|
+
seconds: call.seconds,
|
|
321
|
+
size: call.aspect,
|
|
322
|
+
wallMs: since(started),
|
|
323
|
+
});
|
|
324
|
+
return result;
|
|
325
|
+
});
|
|
191
326
|
},
|
|
192
327
|
forPiece: (piece) => stageProviders(deps, context, piece),
|
|
193
328
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { isProviderError } from "../ports/model.js";
|
|
2
|
+
// The second tier of the retry policy. `attempt.ts` retries a failed call a few times within
|
|
3
|
+
// seconds; when those run out on a failure that time can fix, the step is put back to wait
|
|
4
|
+
// and runs again later, so a rate limit, a timeout or a dropped connection costs the user
|
|
5
|
+
// nothing but time. The wait is written down, not held in memory: a restart keeps it.
|
|
6
|
+
// The failures worth waiting out. A refusal, a rejected or missing key, an unsupported
|
|
7
|
+
// request and a lost submission are the provider's final answer (or need a person), so
|
|
8
|
+
// they are shown at once. `other` covers a request the provider rejected as well as an
|
|
9
|
+
// unreadable answer; the quick in-call retries are all it gets.
|
|
10
|
+
export const waitableKinds = ["rate_limit", "timeout", "dropped"];
|
|
11
|
+
// Four waits after the first failed run: about 2, 4, 8 and 16 minutes, 30 in all.
|
|
12
|
+
export const autoRetryLimit = 4;
|
|
13
|
+
export const autoRetryBaseMs = 2 * 60_000;
|
|
14
|
+
// ±25 %, so a burst of steps that hit the same limit together do not all return together.
|
|
15
|
+
export const autoRetryJitter = 0.25;
|
|
16
|
+
// A provider asking for longer than this (a daily quota) is reported rather than waited on.
|
|
17
|
+
export const retryAfterCeilingMs = 60 * 60_000;
|
|
18
|
+
// A slice may wrap the wrapper's error in its own sentence ("Image 3: ..."); the kind is on
|
|
19
|
+
// the cause.
|
|
20
|
+
export function faultOf(error) {
|
|
21
|
+
let current = error;
|
|
22
|
+
for (let depth = 0; depth < 6 && current !== undefined && current !== null; depth += 1) {
|
|
23
|
+
if (isProviderError(current))
|
|
24
|
+
return current.fault;
|
|
25
|
+
current = current instanceof Error ? current.cause : undefined;
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
// `retries` is how many waits the step already had. Undefined: report the failure now.
|
|
30
|
+
export function autoRetryDelay(fault, retries, random) {
|
|
31
|
+
if (fault === undefined || !waitableKinds.includes(fault.kind))
|
|
32
|
+
return undefined;
|
|
33
|
+
if (retries >= autoRetryLimit)
|
|
34
|
+
return undefined;
|
|
35
|
+
const nominal = autoRetryBaseMs * 2 ** retries;
|
|
36
|
+
const jittered = Math.round(nominal * (1 - autoRetryJitter + 2 * autoRetryJitter * random()));
|
|
37
|
+
if (fault.retryAfterMs === undefined)
|
|
38
|
+
return jittered;
|
|
39
|
+
if (fault.retryAfterMs > retryAfterCeilingMs)
|
|
40
|
+
return undefined;
|
|
41
|
+
// The provider's own wait is the floor; ours still spreads the burst above it.
|
|
42
|
+
return Math.max(fault.retryAfterMs, jittered);
|
|
43
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { isProviderError } from "../ports/model.js";
|
|
2
|
+
import { attempt } from "./attempt.js";
|
|
3
|
+
export async function standaloneLlm(deps, call) {
|
|
4
|
+
const port = deps.registry.llm(call.provider);
|
|
5
|
+
const started = deps.clock.now().getTime();
|
|
6
|
+
const answer = await wrapped(deps, call, async (signal, progress) => {
|
|
7
|
+
let text = "";
|
|
8
|
+
let usage = null;
|
|
9
|
+
let limits;
|
|
10
|
+
for await (const event of port.complete({
|
|
11
|
+
model: call.model,
|
|
12
|
+
...(call.thinking === undefined ? {} : { thinking: call.thinking }),
|
|
13
|
+
messages: call.messages,
|
|
14
|
+
signal,
|
|
15
|
+
})) {
|
|
16
|
+
signal.throwIfAborted();
|
|
17
|
+
// Every event is a sign of life, so the idle clock restarts here.
|
|
18
|
+
progress();
|
|
19
|
+
if (event.type === "delta")
|
|
20
|
+
text += event.text;
|
|
21
|
+
else if (event.type === "done") {
|
|
22
|
+
usage = event.usage;
|
|
23
|
+
limits = event.limits;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return { text, usage, ...(limits === undefined ? {} : { limits }) };
|
|
27
|
+
}, { kind: "llm", streaming: port.capabilities.streams });
|
|
28
|
+
meter(deps, call, {
|
|
29
|
+
kind: "llm",
|
|
30
|
+
provider: call.provider,
|
|
31
|
+
model: answer.usage?.model ?? call.model,
|
|
32
|
+
...tokens(answer.usage ?? undefined),
|
|
33
|
+
wallMs: Math.max(0, deps.clock.now().getTime() - started),
|
|
34
|
+
...(answer.limits === undefined ? {} : { limits: answer.limits }),
|
|
35
|
+
});
|
|
36
|
+
return answer;
|
|
37
|
+
}
|
|
38
|
+
export async function standaloneImage(deps, call) {
|
|
39
|
+
const port = deps.registry.image(call.provider);
|
|
40
|
+
const started = deps.clock.now().getTime();
|
|
41
|
+
const image = await wrapped(deps, call, (signal) => port.generate({
|
|
42
|
+
model: call.model,
|
|
43
|
+
prompt: call.prompt,
|
|
44
|
+
aspect: call.aspect,
|
|
45
|
+
signal,
|
|
46
|
+
}), { kind: "image", ...(port.timeoutMs === undefined ? {} : { timeoutMs: port.timeoutMs }) });
|
|
47
|
+
meter(deps, call, {
|
|
48
|
+
kind: "image",
|
|
49
|
+
provider: call.provider,
|
|
50
|
+
model: call.model,
|
|
51
|
+
images: 1,
|
|
52
|
+
size: call.aspect,
|
|
53
|
+
...tokens(image.usage),
|
|
54
|
+
wallMs: Math.max(0, deps.clock.now().getTime() - started),
|
|
55
|
+
...(image.limits === undefined ? {} : { limits: image.limits }),
|
|
56
|
+
});
|
|
57
|
+
return image;
|
|
58
|
+
}
|
|
59
|
+
async function wrapped(deps, use, call, opts) {
|
|
60
|
+
// The wrapper names its log lines by project and stage; these name what the call was for.
|
|
61
|
+
const label = `${use.purpose}:${use.owner.kind}:${use.owner.id}`;
|
|
62
|
+
let next = 0;
|
|
63
|
+
const attempts = {
|
|
64
|
+
start: () => {
|
|
65
|
+
next += 1;
|
|
66
|
+
return String(next);
|
|
67
|
+
},
|
|
68
|
+
end: () => { },
|
|
69
|
+
};
|
|
70
|
+
const stage = opts.kind === "image" ? "images" : "article";
|
|
71
|
+
try {
|
|
72
|
+
const result = await attempt({
|
|
73
|
+
work: {
|
|
74
|
+
projectId: label,
|
|
75
|
+
revisionId: label,
|
|
76
|
+
workId: label,
|
|
77
|
+
stageId: label,
|
|
78
|
+
kind: stage,
|
|
79
|
+
fingerprint: label,
|
|
80
|
+
},
|
|
81
|
+
maySubmit: () => true,
|
|
82
|
+
clock: deps.clock,
|
|
83
|
+
log: deps.log,
|
|
84
|
+
attempts,
|
|
85
|
+
projectId: label,
|
|
86
|
+
stage,
|
|
87
|
+
stageId: label,
|
|
88
|
+
signal: use.signal ?? new AbortController().signal,
|
|
89
|
+
}, call, opts);
|
|
90
|
+
if (!result.ok)
|
|
91
|
+
throw new Error("The provider did not take the request.");
|
|
92
|
+
return result.value;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
throw standaloneError(error);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// The wrapper's own advice points at a stage's buttons ("use Try again"); a standalone call
|
|
99
|
+
// has none, and each caller says itself where to go next, so that advice is dropped.
|
|
100
|
+
function standaloneError(error) {
|
|
101
|
+
if (!isProviderError(error))
|
|
102
|
+
return error;
|
|
103
|
+
const kept = error.message
|
|
104
|
+
.replace(/,? then use (?:Retry stage|Try again)(?:, or choose another model in the Providers section of Edit project)?/g, "")
|
|
105
|
+
.split(/(?<=\.)\s+/)
|
|
106
|
+
.filter((sentence) => !/Retry stage|Try again|Edit project/.test(sentence))
|
|
107
|
+
.join(" ")
|
|
108
|
+
.trim();
|
|
109
|
+
if (kept === error.message || kept === "")
|
|
110
|
+
return error;
|
|
111
|
+
return Object.assign(new Error(kept, { cause: error }), { fault: error.fault });
|
|
112
|
+
}
|
|
113
|
+
function tokens(usage) {
|
|
114
|
+
if (usage === undefined)
|
|
115
|
+
return {};
|
|
116
|
+
return {
|
|
117
|
+
tokensIn: usage.inputTokens,
|
|
118
|
+
tokensOut: usage.outputTokens,
|
|
119
|
+
...(usage.cachedInputTokens === undefined ? {} : { cachedTokens: usage.cachedInputTokens }),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// Metering never fails a call: the answer is already paid for.
|
|
123
|
+
function meter(deps, use, call) {
|
|
124
|
+
if (deps.meter === undefined)
|
|
125
|
+
return;
|
|
126
|
+
try {
|
|
127
|
+
deps.meter.record({ ...call, owner: use.owner, purpose: use.purpose });
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
deps.log.write("warn", "usage.record", {
|
|
131
|
+
detail: `${use.purpose} for ${use.owner.kind} ${use.owner.id}: ${error instanceof Error ? error.message : String(error)}`,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -29,9 +29,35 @@ export function ownsCurrentWork(db, work, pieceId) {
|
|
|
29
29
|
.prepare(`SELECT 1 FROM revision_work_reservations r JOIN project_heads h ON h.project_id=r.project_id AND h.revision_id=r.revision_id JOIN project_revisions v ON v.id=r.revision_id JOIN json_each(v.fingerprints) f ON f.key=COALESCE(r.logical_key,r.work_key) AND f.value=COALESCE(r.desired_fingerprint,r.fingerprint) WHERE r.project_id=? AND r.work_id=? AND r.piece_id IS ? AND (r.piece_id IS NULL OR EXISTS(SELECT 1 FROM revision_work_pieces p WHERE p.id=r.piece_id AND p.work_id=r.work_id AND p.work_key=r.work_key AND p.fingerprint=r.fingerprint))`)
|
|
30
30
|
.get(work.projectId, work.workId, pieceId) !== undefined);
|
|
31
31
|
}
|
|
32
|
-
export function finishWork(db, work, state, reason) {
|
|
32
|
+
export function finishWork(db, work, state, reason, kind = null) {
|
|
33
33
|
if (!workExists(db, work))
|
|
34
34
|
return;
|
|
35
35
|
const normalized = state === "provided" || state === "skipped" ? "done" : state;
|
|
36
|
-
db.prepare(`UPDATE revision_work SET state=?,failure_reason=?,dispatch_state=CASE WHEN ?='pending' THEN 'held' ELSE dispatch_state END WHERE id=?`).run(normalized, reason, normalized, work.workId);
|
|
36
|
+
db.prepare(`UPDATE revision_work SET state=?,failure_reason=?,failure_kind=?,retry_at=NULL,dispatch_state=CASE WHEN ?='pending' THEN 'held' ELSE dispatch_state END WHERE id=?`).run(normalized, reason, normalized === "failed" ? kind : null, normalized, work.workId);
|
|
37
|
+
}
|
|
38
|
+
// How many times the automatic retry already put this step back to wait.
|
|
39
|
+
export function autoRetriesOf(db, work) {
|
|
40
|
+
const row = db.prepare("SELECT auto_retries FROM revision_work WHERE id=?").get(work.workId);
|
|
41
|
+
return typeof row?.auto_retries === "number" ? row.auto_retries : 0;
|
|
42
|
+
}
|
|
43
|
+
// A running step that failed on something time can fix goes back to `pending` with the time
|
|
44
|
+
// it may start again. It stays dispatchable, unlike a paused one, and its unfinished pieces
|
|
45
|
+
// may be sent again: the failure that ended them was not a lost submission.
|
|
46
|
+
export function deferWork(db, work, at, reason, kind) {
|
|
47
|
+
if (!workExists(db, work))
|
|
48
|
+
return false;
|
|
49
|
+
const moved = db
|
|
50
|
+
.prepare(`UPDATE revision_work SET state='pending',retry_at=?,auto_retries=auto_retries+1,failure_reason=?,failure_kind=? WHERE id=? AND state='running' AND dispatch_state='allowed'`)
|
|
51
|
+
.run(at, reason, kind, work.workId).changes === 1;
|
|
52
|
+
if (moved)
|
|
53
|
+
db.prepare("UPDATE revision_work_pieces SET state='pending' WHERE work_id=? AND state IN ('failed','running')").run(work.workId);
|
|
54
|
+
return moved;
|
|
55
|
+
}
|
|
56
|
+
// The projects with a wait that has run out, their wait cleared so the next tick may claim
|
|
57
|
+
// them. A paused project keeps its wait: Resume ticks it, and nothing else should.
|
|
58
|
+
export function dueRetries(db, now) {
|
|
59
|
+
const rows = db
|
|
60
|
+
.prepare(`UPDATE revision_work SET retry_at=NULL WHERE state='pending' AND retry_at IS NOT NULL AND retry_at<=? AND NOT EXISTS(SELECT 1 FROM project_controls c WHERE c.project_id=revision_work.project_id AND c.paused=1) RETURNING project_id`)
|
|
61
|
+
.all(now);
|
|
62
|
+
return [...new Set(rows.map((row) => String(row.project_id)))];
|
|
37
63
|
}
|