@nodetool-ai/agents 0.7.0-rc.23 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -0
- package/dist/.nodetool-build-stamp +1 -0
- package/dist/analysis/audio-dsp.d.ts +223 -0
- package/dist/analysis/audio-dsp.d.ts.map +1 -0
- package/dist/analysis/audio-dsp.js +642 -0
- package/dist/analysis/audio-dsp.js.map +1 -0
- package/dist/analysis/media-decode.d.ts +85 -0
- package/dist/analysis/media-decode.d.ts.map +1 -0
- package/dist/analysis/media-decode.js +199 -0
- package/dist/analysis/media-decode.js.map +1 -0
- package/dist/analysis/mediabunny-runtime.d.ts +15 -0
- package/dist/analysis/mediabunny-runtime.d.ts.map +1 -0
- package/dist/analysis/mediabunny-runtime.js +30 -0
- package/dist/analysis/mediabunny-runtime.js.map +1 -0
- package/dist/analysis/video-frames.d.ts +120 -0
- package/dist/analysis/video-frames.d.ts.map +1 -0
- package/dist/analysis/video-frames.js +288 -0
- package/dist/analysis/video-frames.js.map +1 -0
- package/dist/apify/assets.d.ts +80 -0
- package/dist/apify/assets.d.ts.map +1 -0
- package/dist/apify/assets.js +192 -0
- package/dist/apify/assets.js.map +1 -0
- package/dist/apify/catalog.d.ts +44 -0
- package/dist/apify/catalog.d.ts.map +1 -0
- package/dist/apify/catalog.js +108 -0
- package/dist/apify/catalog.js.map +1 -0
- package/dist/apify/client.d.ts +137 -0
- package/dist/apify/client.d.ts.map +1 -0
- package/dist/apify/client.js +346 -0
- package/dist/apify/client.js.map +1 -0
- package/dist/apify/errors.d.ts +85 -0
- package/dist/apify/errors.d.ts.map +1 -0
- package/dist/apify/errors.js +90 -0
- package/dist/apify/errors.js.map +1 -0
- package/dist/apify/normalize.d.ts +131 -0
- package/dist/apify/normalize.d.ts.map +1 -0
- package/dist/apify/normalize.js +202 -0
- package/dist/apify/normalize.js.map +1 -0
- package/dist/apify/policy.d.ts +136 -0
- package/dist/apify/policy.d.ts.map +1 -0
- package/dist/apify/policy.js +223 -0
- package/dist/apify/policy.js.map +1 -0
- package/dist/apify/run.d.ts +86 -0
- package/dist/apify/run.d.ts.map +1 -0
- package/dist/apify/run.js +158 -0
- package/dist/apify/run.js.map +1 -0
- package/dist/app-build/author.d.ts +67 -0
- package/dist/app-build/author.d.ts.map +1 -0
- package/dist/app-build/author.js +231 -0
- package/dist/app-build/author.js.map +1 -0
- package/dist/app-build/bridge.d.ts +130 -0
- package/dist/app-build/bridge.d.ts.map +1 -0
- package/dist/app-build/bridge.js +647 -0
- package/dist/app-build/bridge.js.map +1 -0
- package/dist/app-build/build-service.d.ts +66 -0
- package/dist/app-build/build-service.d.ts.map +1 -0
- package/dist/app-build/build-service.js +249 -0
- package/dist/app-build/build-service.js.map +1 -0
- package/dist/app-build/build.d.ts +115 -0
- package/dist/app-build/build.d.ts.map +1 -0
- package/dist/app-build/build.js +901 -0
- package/dist/app-build/build.js.map +1 -0
- package/dist/app-build/interactions.d.ts +20 -0
- package/dist/app-build/interactions.d.ts.map +1 -0
- package/dist/app-build/interactions.js +121 -0
- package/dist/app-build/interactions.js.map +1 -0
- package/dist/app-build/judge.d.ts +113 -0
- package/dist/app-build/judge.d.ts.map +1 -0
- package/dist/app-build/judge.js +318 -0
- package/dist/app-build/judge.js.map +1 -0
- package/dist/app-build/markdown.d.ts +10 -0
- package/dist/app-build/markdown.d.ts.map +1 -0
- package/dist/app-build/markdown.js +65 -0
- package/dist/app-build/markdown.js.map +1 -0
- package/dist/app-build/spec.d.ts +228 -0
- package/dist/app-build/spec.d.ts.map +1 -0
- package/dist/app-build/spec.js +651 -0
- package/dist/app-build/spec.js.map +1 -0
- package/dist/app-build/tool-loop.d.ts +84 -0
- package/dist/app-build/tool-loop.d.ts.map +1 -0
- package/dist/app-build/tool-loop.js +113 -0
- package/dist/app-build/tool-loop.js.map +1 -0
- package/dist/app-build/types.d.ts +215 -0
- package/dist/app-build/types.d.ts.map +1 -0
- package/dist/app-build/types.js +28 -0
- package/dist/app-build/types.js.map +1 -0
- package/dist/author-graph.d.ts +91 -0
- package/dist/author-graph.d.ts.map +1 -0
- package/dist/author-graph.js +319 -0
- package/dist/author-graph.js.map +1 -0
- package/dist/background-subtasks.d.ts +79 -0
- package/dist/background-subtasks.d.ts.map +1 -0
- package/dist/background-subtasks.js +139 -0
- package/dist/background-subtasks.js.map +1 -0
- package/dist/blender-gate.d.ts +21 -0
- package/dist/blender-gate.d.ts.map +1 -0
- package/dist/blender-gate.js +27 -0
- package/dist/blender-gate.js.map +1 -0
- package/dist/browser-gate.d.ts +28 -0
- package/dist/browser-gate.d.ts.map +1 -0
- package/dist/browser-gate.js +34 -0
- package/dist/browser-gate.js.map +1 -0
- package/dist/capabilities/adapters.d.ts +36 -0
- package/dist/capabilities/adapters.d.ts.map +1 -0
- package/dist/capabilities/adapters.js +44 -0
- package/dist/capabilities/adapters.js.map +1 -0
- package/dist/capabilities/agents.d.ts +78 -0
- package/dist/capabilities/agents.d.ts.map +1 -0
- package/dist/capabilities/agents.js +366 -0
- package/dist/capabilities/agents.js.map +1 -0
- package/dist/capabilities/agents.specs.d.ts +27 -0
- package/dist/capabilities/agents.specs.d.ts.map +1 -0
- package/dist/capabilities/agents.specs.js +243 -0
- package/dist/capabilities/agents.specs.js.map +1 -0
- package/dist/capabilities/analysis.d.ts +93 -0
- package/dist/capabilities/analysis.d.ts.map +1 -0
- package/dist/capabilities/analysis.js +812 -0
- package/dist/capabilities/analysis.js.map +1 -0
- package/dist/capabilities/analysis.specs.d.ts +39 -0
- package/dist/capabilities/analysis.specs.d.ts.map +1 -0
- package/dist/capabilities/analysis.specs.js +217 -0
- package/dist/capabilities/analysis.specs.js.map +1 -0
- package/dist/capabilities/apify.d.ts +34 -0
- package/dist/capabilities/apify.d.ts.map +1 -0
- package/dist/capabilities/apify.js +449 -0
- package/dist/capabilities/apify.js.map +1 -0
- package/dist/capabilities/apify.specs.d.ts +28 -0
- package/dist/capabilities/apify.specs.d.ts.map +1 -0
- package/dist/capabilities/apify.specs.js +232 -0
- package/dist/capabilities/apify.specs.js.map +1 -0
- package/dist/capabilities/apps.d.ts +40 -0
- package/dist/capabilities/apps.d.ts.map +1 -0
- package/dist/capabilities/apps.js +413 -0
- package/dist/capabilities/apps.js.map +1 -0
- package/dist/capabilities/apps.specs.d.ts +23 -0
- package/dist/capabilities/apps.specs.d.ts.map +1 -0
- package/dist/capabilities/apps.specs.js +236 -0
- package/dist/capabilities/apps.specs.js.map +1 -0
- package/dist/capabilities/args.d.ts +65 -0
- package/dist/capabilities/args.d.ts.map +1 -0
- package/dist/capabilities/args.js +218 -0
- package/dist/capabilities/args.js.map +1 -0
- package/dist/capabilities/assets.d.ts +45 -0
- package/dist/capabilities/assets.d.ts.map +1 -0
- package/dist/capabilities/assets.js +952 -0
- package/dist/capabilities/assets.js.map +1 -0
- package/dist/capabilities/assets.specs.d.ts +54 -0
- package/dist/capabilities/assets.specs.d.ts.map +1 -0
- package/dist/capabilities/assets.specs.js +291 -0
- package/dist/capabilities/assets.specs.js.map +1 -0
- package/dist/capabilities/background-generation.d.ts +14 -0
- package/dist/capabilities/background-generation.d.ts.map +1 -0
- package/dist/capabilities/background-generation.js +29 -0
- package/dist/capabilities/background-generation.js.map +1 -0
- package/dist/capabilities/browser.d.ts +30 -0
- package/dist/capabilities/browser.d.ts.map +1 -0
- package/dist/capabilities/browser.js +250 -0
- package/dist/capabilities/browser.js.map +1 -0
- package/dist/capabilities/browser.specs.d.ts +37 -0
- package/dist/capabilities/browser.specs.d.ts.map +1 -0
- package/dist/capabilities/browser.specs.js +173 -0
- package/dist/capabilities/browser.specs.js.map +1 -0
- package/dist/capabilities/code-grading.d.ts +68 -0
- package/dist/capabilities/code-grading.d.ts.map +1 -0
- package/dist/capabilities/code-grading.js +75 -0
- package/dist/capabilities/code-grading.js.map +1 -0
- package/dist/capabilities/code.d.ts +56 -0
- package/dist/capabilities/code.d.ts.map +1 -0
- package/dist/capabilities/code.js +327 -0
- package/dist/capabilities/code.js.map +1 -0
- package/dist/capabilities/code.specs.d.ts +22 -0
- package/dist/capabilities/code.specs.d.ts.map +1 -0
- package/dist/capabilities/code.specs.js +175 -0
- package/dist/capabilities/code.specs.js.map +1 -0
- package/dist/capabilities/collections.d.ts +44 -0
- package/dist/capabilities/collections.d.ts.map +1 -0
- package/dist/capabilities/collections.js +432 -0
- package/dist/capabilities/collections.js.map +1 -0
- package/dist/capabilities/collections.specs.d.ts +25 -0
- package/dist/capabilities/collections.specs.d.ts.map +1 -0
- package/dist/capabilities/collections.specs.js +299 -0
- package/dist/capabilities/collections.specs.js.map +1 -0
- package/dist/capabilities/compositions.d.ts +57 -0
- package/dist/capabilities/compositions.d.ts.map +1 -0
- package/dist/capabilities/compositions.js +384 -0
- package/dist/capabilities/compositions.js.map +1 -0
- package/dist/capabilities/compositions.specs.d.ts +22 -0
- package/dist/capabilities/compositions.specs.d.ts.map +1 -0
- package/dist/capabilities/compositions.specs.js +126 -0
- package/dist/capabilities/compositions.specs.js.map +1 -0
- package/dist/capabilities/concurrency.d.ts +12 -0
- package/dist/capabilities/concurrency.d.ts.map +1 -0
- package/dist/capabilities/concurrency.js +30 -0
- package/dist/capabilities/concurrency.js.map +1 -0
- package/dist/capabilities/costs.d.ts +20 -0
- package/dist/capabilities/costs.d.ts.map +1 -0
- package/dist/capabilities/costs.js +40 -0
- package/dist/capabilities/costs.js.map +1 -0
- package/dist/capabilities/costs.specs.d.ts +12 -0
- package/dist/capabilities/costs.specs.d.ts.map +1 -0
- package/dist/capabilities/costs.specs.js +35 -0
- package/dist/capabilities/costs.specs.js.map +1 -0
- package/dist/capabilities/dispatcher.d.ts +57 -0
- package/dist/capabilities/dispatcher.d.ts.map +1 -0
- package/dist/capabilities/dispatcher.js +117 -0
- package/dist/capabilities/dispatcher.js.map +1 -0
- package/dist/capabilities/documents.d.ts +25 -0
- package/dist/capabilities/documents.d.ts.map +1 -0
- package/dist/capabilities/documents.js +278 -0
- package/dist/capabilities/documents.js.map +1 -0
- package/dist/capabilities/documents.specs.d.ts +18 -0
- package/dist/capabilities/documents.specs.d.ts.map +1 -0
- package/dist/capabilities/documents.specs.js +201 -0
- package/dist/capabilities/documents.specs.js.map +1 -0
- package/dist/capabilities/email.d.ts +23 -0
- package/dist/capabilities/email.d.ts.map +1 -0
- package/dist/capabilities/email.js +226 -0
- package/dist/capabilities/email.js.map +1 -0
- package/dist/capabilities/email.specs.d.ts +16 -0
- package/dist/capabilities/email.specs.d.ts.map +1 -0
- package/dist/capabilities/email.specs.js +102 -0
- package/dist/capabilities/email.specs.js.map +1 -0
- package/dist/capabilities/entities.d.ts +52 -0
- package/dist/capabilities/entities.d.ts.map +1 -0
- package/dist/capabilities/entities.js +478 -0
- package/dist/capabilities/entities.js.map +1 -0
- package/dist/capabilities/entities.specs.d.ts +25 -0
- package/dist/capabilities/entities.specs.d.ts.map +1 -0
- package/dist/capabilities/entities.specs.js +247 -0
- package/dist/capabilities/entities.specs.js.map +1 -0
- package/dist/capabilities/example-timelines.d.ts +3 -0
- package/dist/capabilities/example-timelines.d.ts.map +1 -0
- package/dist/capabilities/example-timelines.js +191 -0
- package/dist/capabilities/example-timelines.js.map +1 -0
- package/dist/capabilities/example-timelines.specs.d.ts +5 -0
- package/dist/capabilities/example-timelines.specs.d.ts.map +1 -0
- package/dist/capabilities/example-timelines.specs.js +53 -0
- package/dist/capabilities/example-timelines.specs.js.map +1 -0
- package/dist/capabilities/files.d.ts +53 -0
- package/dist/capabilities/files.d.ts.map +1 -0
- package/dist/capabilities/files.js +1172 -0
- package/dist/capabilities/files.js.map +1 -0
- package/dist/capabilities/files.specs.d.ts +28 -0
- package/dist/capabilities/files.specs.d.ts.map +1 -0
- package/dist/capabilities/files.specs.js +259 -0
- package/dist/capabilities/files.specs.js.map +1 -0
- package/dist/capabilities/flow.d.ts +93 -0
- package/dist/capabilities/flow.d.ts.map +1 -0
- package/dist/capabilities/flow.js +285 -0
- package/dist/capabilities/flow.js.map +1 -0
- package/dist/capabilities/flow.specs.d.ts +25 -0
- package/dist/capabilities/flow.specs.d.ts.map +1 -0
- package/dist/capabilities/flow.specs.js +114 -0
- package/dist/capabilities/flow.specs.js.map +1 -0
- package/dist/capabilities/game-asset-source.d.ts +31 -0
- package/dist/capabilities/game-asset-source.d.ts.map +1 -0
- package/dist/capabilities/game-asset-source.js +81 -0
- package/dist/capabilities/game-asset-source.js.map +1 -0
- package/dist/capabilities/game.d.ts +12 -0
- package/dist/capabilities/game.d.ts.map +1 -0
- package/dist/capabilities/game.js +1262 -0
- package/dist/capabilities/game.js.map +1 -0
- package/dist/capabilities/game.specs.d.ts +3 -0
- package/dist/capabilities/game.specs.d.ts.map +1 -0
- package/dist/capabilities/game.specs.js +96 -0
- package/dist/capabilities/game.specs.js.map +1 -0
- package/dist/capabilities/gate-from-context.d.ts +39 -0
- package/dist/capabilities/gate-from-context.d.ts.map +1 -0
- package/dist/capabilities/gate-from-context.js +97 -0
- package/dist/capabilities/gate-from-context.js.map +1 -0
- package/dist/capabilities/gate-tools.d.ts +18 -0
- package/dist/capabilities/gate-tools.d.ts.map +1 -0
- package/dist/capabilities/gate-tools.js +66 -0
- package/dist/capabilities/gate-tools.js.map +1 -0
- package/dist/capabilities/generations.d.ts +79 -0
- package/dist/capabilities/generations.d.ts.map +1 -0
- package/dist/capabilities/generations.js +382 -0
- package/dist/capabilities/generations.js.map +1 -0
- package/dist/capabilities/generations.specs.d.ts +62 -0
- package/dist/capabilities/generations.specs.d.ts.map +1 -0
- package/dist/capabilities/generations.specs.js +230 -0
- package/dist/capabilities/generations.specs.js.map +1 -0
- package/dist/capabilities/google.d.ts +50 -0
- package/dist/capabilities/google.d.ts.map +1 -0
- package/dist/capabilities/google.js +246 -0
- package/dist/capabilities/google.js.map +1 -0
- package/dist/capabilities/google.specs.d.ts +52 -0
- package/dist/capabilities/google.specs.d.ts.map +1 -0
- package/dist/capabilities/google.specs.js +391 -0
- package/dist/capabilities/google.specs.js.map +1 -0
- package/dist/capabilities/html-text.d.ts +28 -0
- package/dist/capabilities/html-text.d.ts.map +1 -0
- package/dist/capabilities/html-text.js +76 -0
- package/dist/capabilities/html-text.js.map +1 -0
- package/dist/capabilities/index.d.ts +19 -0
- package/dist/capabilities/index.d.ts.map +1 -0
- package/dist/capabilities/index.js +14 -0
- package/dist/capabilities/index.js.map +1 -0
- package/dist/capabilities/invoke.d.ts +89 -0
- package/dist/capabilities/invoke.d.ts.map +1 -0
- package/dist/capabilities/invoke.js +214 -0
- package/dist/capabilities/invoke.js.map +1 -0
- package/dist/capabilities/jobs.d.ts +32 -0
- package/dist/capabilities/jobs.d.ts.map +1 -0
- package/dist/capabilities/jobs.js +123 -0
- package/dist/capabilities/jobs.js.map +1 -0
- package/dist/capabilities/jobs.specs.d.ts +20 -0
- package/dist/capabilities/jobs.specs.d.ts.map +1 -0
- package/dist/capabilities/jobs.specs.js +103 -0
- package/dist/capabilities/jobs.specs.js.map +1 -0
- package/dist/capabilities/js-scripts.d.ts +90 -0
- package/dist/capabilities/js-scripts.d.ts.map +1 -0
- package/dist/capabilities/js-scripts.js +700 -0
- package/dist/capabilities/js-scripts.js.map +1 -0
- package/dist/capabilities/js-scripts.specs.d.ts +50 -0
- package/dist/capabilities/js-scripts.specs.d.ts.map +1 -0
- package/dist/capabilities/js-scripts.specs.js +344 -0
- package/dist/capabilities/js-scripts.specs.js.map +1 -0
- package/dist/capabilities/lazy-tool.d.ts +42 -0
- package/dist/capabilities/lazy-tool.d.ts.map +1 -0
- package/dist/capabilities/lazy-tool.js +88 -0
- package/dist/capabilities/lazy-tool.js.map +1 -0
- package/dist/capabilities/local-browser.d.ts +24 -0
- package/dist/capabilities/local-browser.d.ts.map +1 -0
- package/dist/capabilities/local-browser.js +105 -0
- package/dist/capabilities/local-browser.js.map +1 -0
- package/dist/capabilities/media.d.ts +121 -0
- package/dist/capabilities/media.d.ts.map +1 -0
- package/dist/capabilities/media.js +2217 -0
- package/dist/capabilities/media.js.map +1 -0
- package/dist/capabilities/media.specs.d.ts +65 -0
- package/dist/capabilities/media.specs.d.ts.map +1 -0
- package/dist/capabilities/media.specs.js +779 -0
- package/dist/capabilities/media.specs.js.map +1 -0
- package/dist/capabilities/memory.d.ts +31 -0
- package/dist/capabilities/memory.d.ts.map +1 -0
- package/dist/capabilities/memory.js +403 -0
- package/dist/capabilities/memory.js.map +1 -0
- package/dist/capabilities/memory.specs.d.ts +55 -0
- package/dist/capabilities/memory.specs.d.ts.map +1 -0
- package/dist/capabilities/memory.specs.js +208 -0
- package/dist/capabilities/memory.specs.js.map +1 -0
- package/dist/capabilities/model3d.d.ts +29 -0
- package/dist/capabilities/model3d.d.ts.map +1 -0
- package/dist/capabilities/model3d.js +482 -0
- package/dist/capabilities/model3d.js.map +1 -0
- package/dist/capabilities/model3d.specs.d.ts +28 -0
- package/dist/capabilities/model3d.specs.d.ts.map +1 -0
- package/dist/capabilities/model3d.specs.js +305 -0
- package/dist/capabilities/model3d.specs.js.map +1 -0
- package/dist/capabilities/models.d.ts +138 -0
- package/dist/capabilities/models.d.ts.map +1 -0
- package/dist/capabilities/models.js +803 -0
- package/dist/capabilities/models.js.map +1 -0
- package/dist/capabilities/models.specs.d.ts +21 -0
- package/dist/capabilities/models.specs.d.ts.map +1 -0
- package/dist/capabilities/models.specs.js +141 -0
- package/dist/capabilities/models.specs.js.map +1 -0
- package/dist/capabilities/nodes.d.ts +26 -0
- package/dist/capabilities/nodes.d.ts.map +1 -0
- package/dist/capabilities/nodes.js +266 -0
- package/dist/capabilities/nodes.js.map +1 -0
- package/dist/capabilities/nodes.specs.d.ts +20 -0
- package/dist/capabilities/nodes.specs.d.ts.map +1 -0
- package/dist/capabilities/nodes.specs.js +106 -0
- package/dist/capabilities/nodes.specs.js.map +1 -0
- package/dist/capabilities/packs.d.ts +69 -0
- package/dist/capabilities/packs.d.ts.map +1 -0
- package/dist/capabilities/packs.js +246 -0
- package/dist/capabilities/packs.js.map +1 -0
- package/dist/capabilities/packs.specs.d.ts +27 -0
- package/dist/capabilities/packs.specs.d.ts.map +1 -0
- package/dist/capabilities/packs.specs.js +64 -0
- package/dist/capabilities/packs.specs.js.map +1 -0
- package/dist/capabilities/project-scope.d.ts +12 -0
- package/dist/capabilities/project-scope.d.ts.map +1 -0
- package/dist/capabilities/project-scope.js +19 -0
- package/dist/capabilities/project-scope.js.map +1 -0
- package/dist/capabilities/projects.d.ts +23 -0
- package/dist/capabilities/projects.d.ts.map +1 -0
- package/dist/capabilities/projects.js +206 -0
- package/dist/capabilities/projects.js.map +1 -0
- package/dist/capabilities/projects.specs.d.ts +23 -0
- package/dist/capabilities/projects.specs.d.ts.map +1 -0
- package/dist/capabilities/projects.specs.js +118 -0
- package/dist/capabilities/projects.specs.js.map +1 -0
- package/dist/capabilities/registry.d.ts +109 -0
- package/dist/capabilities/registry.d.ts.map +1 -0
- package/dist/capabilities/registry.js +445 -0
- package/dist/capabilities/registry.js.map +1 -0
- package/dist/capabilities/script-link.d.ts +22 -0
- package/dist/capabilities/script-link.d.ts.map +1 -0
- package/dist/capabilities/script-link.js +35 -0
- package/dist/capabilities/script-link.js.map +1 -0
- package/dist/capabilities/scripts.d.ts +43 -0
- package/dist/capabilities/scripts.d.ts.map +1 -0
- package/dist/capabilities/scripts.js +1789 -0
- package/dist/capabilities/scripts.js.map +1 -0
- package/dist/capabilities/scripts.specs.d.ts +40 -0
- package/dist/capabilities/scripts.specs.d.ts.map +1 -0
- package/dist/capabilities/scripts.specs.js +319 -0
- package/dist/capabilities/scripts.specs.js.map +1 -0
- package/dist/capabilities/serpapi.d.ts +42 -0
- package/dist/capabilities/serpapi.d.ts.map +1 -0
- package/dist/capabilities/serpapi.js +262 -0
- package/dist/capabilities/serpapi.js.map +1 -0
- package/dist/capabilities/serpapi.specs.d.ts +24 -0
- package/dist/capabilities/serpapi.specs.d.ts.map +1 -0
- package/dist/capabilities/serpapi.specs.js +174 -0
- package/dist/capabilities/serpapi.specs.js.map +1 -0
- package/dist/capabilities/settings.d.ts +48 -0
- package/dist/capabilities/settings.d.ts.map +1 -0
- package/dist/capabilities/settings.js +226 -0
- package/dist/capabilities/settings.js.map +1 -0
- package/dist/capabilities/settings.specs.d.ts +42 -0
- package/dist/capabilities/settings.specs.d.ts.map +1 -0
- package/dist/capabilities/settings.specs.js +126 -0
- package/dist/capabilities/settings.specs.js.map +1 -0
- package/dist/capabilities/shared.d.ts +35 -0
- package/dist/capabilities/shared.d.ts.map +1 -0
- package/dist/capabilities/shared.js +165 -0
- package/dist/capabilities/shared.js.map +1 -0
- package/dist/capabilities/shared.specs.d.ts +19 -0
- package/dist/capabilities/shared.specs.d.ts.map +1 -0
- package/dist/capabilities/shared.specs.js +134 -0
- package/dist/capabilities/shared.specs.js.map +1 -0
- package/dist/capabilities/sketches.d.ts +52 -0
- package/dist/capabilities/sketches.d.ts.map +1 -0
- package/dist/capabilities/sketches.js +1163 -0
- package/dist/capabilities/sketches.js.map +1 -0
- package/dist/capabilities/sketches.specs.d.ts +44 -0
- package/dist/capabilities/sketches.specs.d.ts.map +1 -0
- package/dist/capabilities/sketches.specs.js +392 -0
- package/dist/capabilities/sketches.specs.js.map +1 -0
- package/dist/capabilities/skills.d.ts +28 -0
- package/dist/capabilities/skills.d.ts.map +1 -0
- package/dist/capabilities/skills.js +269 -0
- package/dist/capabilities/skills.js.map +1 -0
- package/dist/capabilities/skills.specs.d.ts +17 -0
- package/dist/capabilities/skills.specs.d.ts.map +1 -0
- package/dist/capabilities/skills.specs.js +108 -0
- package/dist/capabilities/skills.specs.js.map +1 -0
- package/dist/capabilities/storyboards.d.ts +68 -0
- package/dist/capabilities/storyboards.d.ts.map +1 -0
- package/dist/capabilities/storyboards.js +2246 -0
- package/dist/capabilities/storyboards.js.map +1 -0
- package/dist/capabilities/storyboards.specs.d.ts +42 -0
- package/dist/capabilities/storyboards.specs.d.ts.map +1 -0
- package/dist/capabilities/storyboards.specs.js +418 -0
- package/dist/capabilities/storyboards.specs.js.map +1 -0
- package/dist/capabilities/threads.d.ts +25 -0
- package/dist/capabilities/threads.d.ts.map +1 -0
- package/dist/capabilities/threads.js +240 -0
- package/dist/capabilities/threads.js.map +1 -0
- package/dist/capabilities/threads.specs.d.ts +26 -0
- package/dist/capabilities/threads.specs.d.ts.map +1 -0
- package/dist/capabilities/threads.specs.js +108 -0
- package/dist/capabilities/threads.specs.js.map +1 -0
- package/dist/capabilities/timeline-audio-bake.d.ts +114 -0
- package/dist/capabilities/timeline-audio-bake.d.ts.map +1 -0
- package/dist/capabilities/timeline-audio-bake.js +188 -0
- package/dist/capabilities/timeline-audio-bake.js.map +1 -0
- package/dist/capabilities/timeline-bake.d.ts +21 -0
- package/dist/capabilities/timeline-bake.d.ts.map +1 -0
- package/dist/capabilities/timeline-bake.js +118 -0
- package/dist/capabilities/timeline-bake.js.map +1 -0
- package/dist/capabilities/timeline-isolate-subject.d.ts +157 -0
- package/dist/capabilities/timeline-isolate-subject.d.ts.map +1 -0
- package/dist/capabilities/timeline-isolate-subject.js +293 -0
- package/dist/capabilities/timeline-isolate-subject.js.map +1 -0
- package/dist/capabilities/timeline-native-media.d.ts +4 -0
- package/dist/capabilities/timeline-native-media.d.ts.map +1 -0
- package/dist/capabilities/timeline-native-media.js +920 -0
- package/dist/capabilities/timeline-native-media.js.map +1 -0
- package/dist/capabilities/timeline-track-object.d.ts +83 -0
- package/dist/capabilities/timeline-track-object.d.ts.map +1 -0
- package/dist/capabilities/timeline-track-object.js +195 -0
- package/dist/capabilities/timeline-track-object.js.map +1 -0
- package/dist/capabilities/timelines.d.ts +190 -0
- package/dist/capabilities/timelines.d.ts.map +1 -0
- package/dist/capabilities/timelines.js +2326 -0
- package/dist/capabilities/timelines.js.map +1 -0
- package/dist/capabilities/timelines.specs.d.ts +134 -0
- package/dist/capabilities/timelines.specs.d.ts.map +1 -0
- package/dist/capabilities/timelines.specs.js +1362 -0
- package/dist/capabilities/timelines.specs.js.map +1 -0
- package/dist/capabilities/types.d.ts +197 -0
- package/dist/capabilities/types.d.ts.map +1 -0
- package/dist/capabilities/types.js +19 -0
- package/dist/capabilities/types.js.map +1 -0
- package/dist/capabilities/ui.d.ts +38 -0
- package/dist/capabilities/ui.d.ts.map +1 -0
- package/dist/capabilities/ui.js +128 -0
- package/dist/capabilities/ui.js.map +1 -0
- package/dist/capabilities/ui.specs.d.ts +22 -0
- package/dist/capabilities/ui.specs.d.ts.map +1 -0
- package/dist/capabilities/ui.specs.js +59 -0
- package/dist/capabilities/ui.specs.js.map +1 -0
- package/dist/capabilities/video-production-acceptance.d.ts +27 -0
- package/dist/capabilities/video-production-acceptance.d.ts.map +1 -0
- package/dist/capabilities/video-production-acceptance.js +41 -0
- package/dist/capabilities/video-production-acceptance.js.map +1 -0
- package/dist/capabilities/video-production.d.ts +179 -0
- package/dist/capabilities/video-production.d.ts.map +1 -0
- package/dist/capabilities/video-production.js +1492 -0
- package/dist/capabilities/video-production.js.map +1 -0
- package/dist/capabilities/video-production.specs.d.ts +13 -0
- package/dist/capabilities/video-production.specs.d.ts.map +1 -0
- package/dist/capabilities/video-production.specs.js +256 -0
- package/dist/capabilities/video-production.specs.js.map +1 -0
- package/dist/capabilities/web.d.ts +86 -0
- package/dist/capabilities/web.d.ts.map +1 -0
- package/dist/capabilities/web.js +850 -0
- package/dist/capabilities/web.js.map +1 -0
- package/dist/capabilities/web.specs.d.ts +33 -0
- package/dist/capabilities/web.specs.d.ts.map +1 -0
- package/dist/capabilities/web.specs.js +286 -0
- package/dist/capabilities/web.specs.js.map +1 -0
- package/dist/capabilities/workflows.d.ts +58 -0
- package/dist/capabilities/workflows.d.ts.map +1 -0
- package/dist/capabilities/workflows.js +1530 -0
- package/dist/capabilities/workflows.js.map +1 -0
- package/dist/capabilities/workflows.specs.d.ts +63 -0
- package/dist/capabilities/workflows.specs.d.ts.map +1 -0
- package/dist/capabilities/workflows.specs.js +852 -0
- package/dist/capabilities/workflows.specs.js.map +1 -0
- package/dist/code-gen/analyze.d.ts +26 -0
- package/dist/code-gen/analyze.d.ts.map +1 -0
- package/dist/code-gen/analyze.js +79 -0
- package/dist/code-gen/analyze.js.map +1 -0
- package/dist/code-gen/port-types.d.ts +58 -0
- package/dist/code-gen/port-types.d.ts.map +1 -0
- package/dist/code-gen/port-types.js +115 -0
- package/dist/code-gen/port-types.js.map +1 -0
- package/dist/code-gen/prompt.d.ts +37 -0
- package/dist/code-gen/prompt.d.ts.map +1 -0
- package/dist/code-gen/prompt.js +129 -0
- package/dist/code-gen/prompt.js.map +1 -0
- package/dist/code-gen/sandbox-manifest.d.ts +120 -0
- package/dist/code-gen/sandbox-manifest.d.ts.map +1 -0
- package/dist/code-gen/sandbox-manifest.js +1023 -0
- package/dist/code-gen/sandbox-manifest.js.map +1 -0
- package/dist/code-gen/sandbox-prompt.d.ts +26 -0
- package/dist/code-gen/sandbox-prompt.d.ts.map +1 -0
- package/dist/code-gen/sandbox-prompt.js +126 -0
- package/dist/code-gen/sandbox-prompt.js.map +1 -0
- package/dist/code-planner.d.ts +72 -0
- package/dist/code-planner.d.ts.map +1 -0
- package/dist/code-planner.js +271 -0
- package/dist/code-planner.js.map +1 -0
- package/dist/codeact/action-diagnostics.d.ts +35 -0
- package/dist/codeact/action-diagnostics.d.ts.map +1 -0
- package/dist/codeact/action-diagnostics.js +147 -0
- package/dist/codeact/action-diagnostics.js.map +1 -0
- package/dist/codeact/capability-modules.d.ts +66 -0
- package/dist/codeact/capability-modules.d.ts.map +1 -0
- package/dist/codeact/capability-modules.js +278 -0
- package/dist/codeact/capability-modules.js.map +1 -0
- package/dist/codeact/chat-codeact.d.ts +104 -0
- package/dist/codeact/chat-codeact.d.ts.map +1 -0
- package/dist/codeact/chat-codeact.js +424 -0
- package/dist/codeact/chat-codeact.js.map +1 -0
- package/dist/codeact/codeact-executor.d.ts +247 -0
- package/dist/codeact/codeact-executor.d.ts.map +1 -0
- package/dist/codeact/codeact-executor.js +1176 -0
- package/dist/codeact/codeact-executor.js.map +1 -0
- package/dist/codeact/compact-ids.d.ts +28 -0
- package/dist/codeact/compact-ids.d.ts.map +1 -0
- package/dist/codeact/compact-ids.js +77 -0
- package/dist/codeact/compact-ids.js.map +1 -0
- package/dist/codeact/execute-code-contract.d.ts +97 -0
- package/dist/codeact/execute-code-contract.d.ts.map +1 -0
- package/dist/codeact/execute-code-contract.js +225 -0
- package/dist/codeact/execute-code-contract.js.map +1 -0
- package/dist/codeact/fabric-package.d.ts +29 -0
- package/dist/codeact/fabric-package.d.ts.map +1 -0
- package/dist/codeact/fabric-package.js +62 -0
- package/dist/codeact/fabric-package.js.map +1 -0
- package/dist/codeact/flow-package.d.ts +31 -0
- package/dist/codeact/flow-package.d.ts.map +1 -0
- package/dist/codeact/flow-package.js +80 -0
- package/dist/codeact/flow-package.js.map +1 -0
- package/dist/codeact/graph-dsl-package.d.ts +42 -0
- package/dist/codeact/graph-dsl-package.d.ts.map +1 -0
- package/dist/codeact/graph-dsl-package.js +100 -0
- package/dist/codeact/graph-dsl-package.js.map +1 -0
- package/dist/codeact/graph-model.d.ts +30 -0
- package/dist/codeact/graph-model.d.ts.map +1 -0
- package/dist/codeact/graph-model.js +408 -0
- package/dist/codeact/graph-model.js.map +1 -0
- package/dist/codeact/mcp-guest-contract.d.ts +66 -0
- package/dist/codeact/mcp-guest-contract.d.ts.map +1 -0
- package/dist/codeact/mcp-guest-contract.js +108 -0
- package/dist/codeact/mcp-guest-contract.js.map +1 -0
- package/dist/codeact/nodetool-api.d.ts +60 -0
- package/dist/codeact/nodetool-api.d.ts.map +1 -0
- package/dist/codeact/nodetool-api.js +2056 -0
- package/dist/codeact/nodetool-api.js.map +1 -0
- package/dist/codeact/prompt.d.ts +88 -0
- package/dist/codeact/prompt.d.ts.map +1 -0
- package/dist/codeact/prompt.js +326 -0
- package/dist/codeact/prompt.js.map +1 -0
- package/dist/codeact/sandbox-package-docs.d.ts +48 -0
- package/dist/codeact/sandbox-package-docs.d.ts.map +1 -0
- package/dist/codeact/sandbox-package-docs.js +55 -0
- package/dist/codeact/sandbox-package-docs.js.map +1 -0
- package/dist/codeact/sandbox-package-listing.d.ts +81 -0
- package/dist/codeact/sandbox-package-listing.d.ts.map +1 -0
- package/dist/codeact/sandbox-package-listing.js +101 -0
- package/dist/codeact/sandbox-package-listing.js.map +1 -0
- package/dist/codeact/sandbox-packages.d.ts +72 -0
- package/dist/codeact/sandbox-packages.d.ts.map +1 -0
- package/dist/codeact/sandbox-packages.js +230 -0
- package/dist/codeact/sandbox-packages.js.map +1 -0
- package/dist/codeact/timeline-package.d.ts +5 -0
- package/dist/codeact/timeline-package.d.ts.map +1 -0
- package/dist/codeact/timeline-package.js +10 -0
- package/dist/codeact/timeline-package.js.map +1 -0
- package/dist/codeact/tool-api.d.ts +197 -0
- package/dist/codeact/tool-api.d.ts.map +1 -0
- package/dist/codeact/tool-api.js +445 -0
- package/dist/codeact/tool-api.js.map +1 -0
- package/dist/codeact/tools-prelude.d.ts +32 -0
- package/dist/codeact/tools-prelude.d.ts.map +1 -0
- package/dist/codeact/tools-prelude.js +65 -0
- package/dist/codeact/tools-prelude.js.map +1 -0
- package/dist/constants.d.ts +47 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +64 -2
- package/dist/constants.js.map +1 -1
- package/dist/custom-animation-bake.d.ts +57 -0
- package/dist/custom-animation-bake.d.ts.map +1 -0
- package/dist/custom-animation-bake.js +88 -0
- package/dist/custom-animation-bake.js.map +1 -0
- package/dist/dynamic-slots.d.ts +72 -0
- package/dist/dynamic-slots.d.ts.map +1 -0
- package/dist/dynamic-slots.js +0 -0
- package/dist/dynamic-slots.js.map +1 -0
- package/dist/evals/app-build-cases.d.ts +35 -0
- package/dist/evals/app-build-cases.d.ts.map +1 -0
- package/dist/evals/app-build-cases.js +722 -0
- package/dist/evals/app-build-cases.js.map +1 -0
- package/dist/evals/app-build-eval.d.ts +208 -0
- package/dist/evals/app-build-eval.d.ts.map +1 -0
- package/dist/evals/app-build-eval.js +518 -0
- package/dist/evals/app-build-eval.js.map +1 -0
- package/dist/evals/app-build-plan.d.ts +76 -0
- package/dist/evals/app-build-plan.d.ts.map +1 -0
- package/dist/evals/app-build-plan.js +140 -0
- package/dist/evals/app-build-plan.js.map +1 -0
- package/dist/evals/code-gen-cases.d.ts +13 -0
- package/dist/evals/code-gen-cases.d.ts.map +1 -0
- package/dist/evals/code-gen-cases.js +124 -0
- package/dist/evals/code-gen-cases.js.map +1 -0
- package/dist/evals/code-gen-eval.d.ts +109 -0
- package/dist/evals/code-gen-eval.d.ts.map +1 -0
- package/dist/evals/code-gen-eval.js +299 -0
- package/dist/evals/code-gen-eval.js.map +1 -0
- package/dist/evals/codeact-api-cases.d.ts +14 -0
- package/dist/evals/codeact-api-cases.d.ts.map +1 -0
- package/dist/evals/codeact-api-cases.js +29 -0
- package/dist/evals/codeact-api-cases.js.map +1 -0
- package/dist/evals/codeact-api-core.d.ts +23 -0
- package/dist/evals/codeact-api-core.d.ts.map +1 -0
- package/dist/evals/codeact-api-core.js +1411 -0
- package/dist/evals/codeact-api-core.js.map +1 -0
- package/dist/evals/codeact-api-surfaces.d.ts +25 -0
- package/dist/evals/codeact-api-surfaces.d.ts.map +1 -0
- package/dist/evals/codeact-api-surfaces.js +2191 -0
- package/dist/evals/codeact-api-surfaces.js.map +1 -0
- package/dist/evals/codeact-cases.d.ts +76 -0
- package/dist/evals/codeact-cases.d.ts.map +1 -0
- package/dist/evals/codeact-cases.js +151 -0
- package/dist/evals/codeact-cases.js.map +1 -0
- package/dist/evals/codeact-eval.d.ts +66 -0
- package/dist/evals/codeact-eval.d.ts.map +1 -0
- package/dist/evals/codeact-eval.js +250 -0
- package/dist/evals/codeact-eval.js.map +1 -0
- package/dist/evals/codeact-sandbox-pack-cases.d.ts +31 -0
- package/dist/evals/codeact-sandbox-pack-cases.d.ts.map +1 -0
- package/dist/evals/codeact-sandbox-pack-cases.js +219 -0
- package/dist/evals/codeact-sandbox-pack-cases.js.map +1 -0
- package/dist/evals/escalation-cases.d.ts +22 -0
- package/dist/evals/escalation-cases.d.ts.map +1 -0
- package/dist/evals/escalation-cases.js +343 -0
- package/dist/evals/escalation-cases.js.map +1 -0
- package/dist/evals/escalation.d.ts +92 -0
- package/dist/evals/escalation.d.ts.map +1 -0
- package/dist/evals/escalation.js +152 -0
- package/dist/evals/escalation.js.map +1 -0
- package/dist/evals/goal-judge.d.ts +51 -0
- package/dist/evals/goal-judge.d.ts.map +1 -0
- package/dist/evals/goal-judge.js +152 -0
- package/dist/evals/goal-judge.js.map +1 -0
- package/dist/evals/graph-e2e-cases.d.ts +21 -0
- package/dist/evals/graph-e2e-cases.d.ts.map +1 -0
- package/dist/evals/graph-e2e-cases.js +262 -0
- package/dist/evals/graph-e2e-cases.js.map +1 -0
- package/dist/evals/graph-e2e-eval.d.ts +202 -0
- package/dist/evals/graph-e2e-eval.d.ts.map +1 -0
- package/dist/evals/graph-e2e-eval.js +438 -0
- package/dist/evals/graph-e2e-eval.js.map +1 -0
- package/dist/evals/graph-planner-cases.d.ts +12 -0
- package/dist/evals/graph-planner-cases.d.ts.map +1 -0
- package/dist/evals/graph-planner-cases.js +256 -0
- package/dist/evals/graph-planner-cases.js.map +1 -0
- package/dist/evals/graph-planner-eval.d.ts +178 -0
- package/dist/evals/graph-planner-eval.d.ts.map +1 -0
- package/dist/evals/graph-planner-eval.js +495 -0
- package/dist/evals/graph-planner-eval.js.map +1 -0
- package/dist/evals/planner-tools.d.ts +21 -0
- package/dist/evals/planner-tools.d.ts.map +1 -0
- package/dist/evals/planner-tools.js +66 -0
- package/dist/evals/planner-tools.js.map +1 -0
- package/dist/evals/subtask-cases.d.ts +88 -0
- package/dist/evals/subtask-cases.d.ts.map +1 -0
- package/dist/evals/subtask-cases.js +322 -0
- package/dist/evals/subtask-cases.js.map +1 -0
- package/dist/evals/subtask-eval.d.ts +129 -0
- package/dist/evals/subtask-eval.d.ts.map +1 -0
- package/dist/evals/subtask-eval.js +397 -0
- package/dist/evals/subtask-eval.js.map +1 -0
- package/dist/evals/surfaces/app.d.ts +19 -0
- package/dist/evals/surfaces/app.d.ts.map +1 -0
- package/dist/evals/surfaces/app.js +341 -0
- package/dist/evals/surfaces/app.js.map +1 -0
- package/dist/evals/surfaces/creative-pipeline.d.ts +203 -0
- package/dist/evals/surfaces/creative-pipeline.d.ts.map +1 -0
- package/dist/evals/surfaces/creative-pipeline.js +909 -0
- package/dist/evals/surfaces/creative-pipeline.js.map +1 -0
- package/dist/evals/surfaces/game.d.ts +5 -0
- package/dist/evals/surfaces/game.d.ts.map +1 -0
- package/dist/evals/surfaces/game.js +42 -0
- package/dist/evals/surfaces/game.js.map +1 -0
- package/dist/evals/surfaces/js-script.d.ts +66 -0
- package/dist/evals/surfaces/js-script.d.ts.map +1 -0
- package/dist/evals/surfaces/js-script.js +407 -0
- package/dist/evals/surfaces/js-script.js.map +1 -0
- package/dist/evals/surfaces/memory.d.ts +34 -0
- package/dist/evals/surfaces/memory.d.ts.map +1 -0
- package/dist/evals/surfaces/memory.js +264 -0
- package/dist/evals/surfaces/memory.js.map +1 -0
- package/dist/evals/surfaces/model3d.d.ts +45 -0
- package/dist/evals/surfaces/model3d.d.ts.map +1 -0
- package/dist/evals/surfaces/model3d.js +346 -0
- package/dist/evals/surfaces/model3d.js.map +1 -0
- package/dist/evals/surfaces/script.d.ts +96 -0
- package/dist/evals/surfaces/script.d.ts.map +1 -0
- package/dist/evals/surfaces/script.js +709 -0
- package/dist/evals/surfaces/script.js.map +1 -0
- package/dist/evals/surfaces/sketch.d.ts +124 -0
- package/dist/evals/surfaces/sketch.d.ts.map +1 -0
- package/dist/evals/surfaces/sketch.js +1298 -0
- package/dist/evals/surfaces/sketch.js.map +1 -0
- package/dist/evals/surfaces/storyboard.d.ts +97 -0
- package/dist/evals/surfaces/storyboard.d.ts.map +1 -0
- package/dist/evals/surfaces/storyboard.js +693 -0
- package/dist/evals/surfaces/storyboard.js.map +1 -0
- package/dist/evals/surfaces/timeline.d.ts +416 -0
- package/dist/evals/surfaces/timeline.d.ts.map +1 -0
- package/dist/evals/surfaces/timeline.js +3267 -0
- package/dist/evals/surfaces/timeline.js.map +1 -0
- package/dist/evals/task-planner-cases.d.ts +57 -0
- package/dist/evals/task-planner-cases.d.ts.map +1 -0
- package/dist/evals/task-planner-cases.js +117 -0
- package/dist/evals/task-planner-cases.js.map +1 -0
- package/dist/evals/task-planner-eval.d.ts +101 -0
- package/dist/evals/task-planner-eval.d.ts.map +1 -0
- package/dist/evals/task-planner-eval.js +380 -0
- package/dist/evals/task-planner-eval.js.map +1 -0
- package/dist/evals/tool-loop-bridge.d.ts +57 -0
- package/dist/evals/tool-loop-bridge.d.ts.map +1 -0
- package/dist/evals/tool-loop-bridge.js +129 -0
- package/dist/evals/tool-loop-bridge.js.map +1 -0
- package/dist/evals/tool-loop-cases.d.ts +21 -0
- package/dist/evals/tool-loop-cases.d.ts.map +1 -0
- package/dist/evals/tool-loop-cases.js +401 -0
- package/dist/evals/tool-loop-cases.js.map +1 -0
- package/dist/evals/tool-loop-eval.d.ts +234 -0
- package/dist/evals/tool-loop-eval.d.ts.map +1 -0
- package/dist/evals/tool-loop-eval.js +373 -0
- package/dist/evals/tool-loop-eval.js.map +1 -0
- package/dist/evals/tool-loop-permission.d.ts +43 -0
- package/dist/evals/tool-loop-permission.d.ts.map +1 -0
- package/dist/evals/tool-loop-permission.js +76 -0
- package/dist/evals/tool-loop-permission.js.map +1 -0
- package/dist/game-examples.d.ts +447 -0
- package/dist/game-examples.d.ts.map +1 -0
- package/dist/game-examples.js +187 -0
- package/dist/game-examples.js.map +1 -0
- package/dist/graph-builder.d.ts +55 -3
- package/dist/graph-builder.d.ts.map +1 -1
- package/dist/graph-builder.js +159 -4
- package/dist/graph-builder.js.map +1 -1
- package/dist/graph-dsl-core.d.ts +25 -0
- package/dist/graph-dsl-core.d.ts.map +1 -0
- package/dist/graph-dsl-core.js +312 -0
- package/dist/graph-dsl-core.js.map +1 -0
- package/dist/graph-dsl.d.ts +30 -0
- package/dist/graph-dsl.d.ts.map +1 -0
- package/dist/graph-dsl.js +116 -0
- package/dist/graph-dsl.js.map +1 -0
- package/dist/host-binaries.d.ts +6 -0
- package/dist/host-binaries.d.ts.map +1 -0
- package/dist/host-binaries.js +6 -0
- package/dist/host-binaries.js.map +1 -0
- package/dist/host-binary-guard.d.ts +100 -0
- package/dist/host-binary-guard.d.ts.map +1 -0
- package/dist/host-binary-guard.js +205 -0
- package/dist/host-binary-guard.js.map +1 -0
- package/dist/host-modules/aws.d.ts +57 -0
- package/dist/host-modules/aws.d.ts.map +1 -0
- package/dist/host-modules/aws.js +309 -0
- package/dist/host-modules/aws.js.map +1 -0
- package/dist/host-modules/chrono.d.ts +15 -0
- package/dist/host-modules/chrono.d.ts.map +1 -0
- package/dist/host-modules/chrono.js +35 -0
- package/dist/host-modules/chrono.js.map +1 -0
- package/dist/host-modules/csv.d.ts +17 -0
- package/dist/host-modules/csv.d.ts.map +1 -0
- package/dist/host-modules/csv.js +64 -0
- package/dist/host-modules/csv.js.map +1 -0
- package/dist/host-modules/diff.d.ts +9 -0
- package/dist/host-modules/diff.d.ts.map +1 -0
- package/dist/host-modules/diff.js +26 -0
- package/dist/host-modules/diff.js.map +1 -0
- package/dist/host-modules/dispatcher.d.ts +41 -0
- package/dist/host-modules/dispatcher.d.ts.map +1 -0
- package/dist/host-modules/dispatcher.js +99 -0
- package/dist/host-modules/dispatcher.js.map +1 -0
- package/dist/host-modules/docx.d.ts +19 -0
- package/dist/host-modules/docx.d.ts.map +1 -0
- package/dist/host-modules/docx.js +120 -0
- package/dist/host-modules/docx.js.map +1 -0
- package/dist/host-modules/epub.d.ts +48 -0
- package/dist/host-modules/epub.d.ts.map +1 -0
- package/dist/host-modules/epub.js +100 -0
- package/dist/host-modules/epub.js.map +1 -0
- package/dist/host-modules/exif.d.ts +8 -0
- package/dist/host-modules/exif.d.ts.map +1 -0
- package/dist/host-modules/exif.js +19 -0
- package/dist/host-modules/exif.js.map +1 -0
- package/dist/host-modules/expr.d.ts +16 -0
- package/dist/host-modules/expr.d.ts.map +1 -0
- package/dist/host-modules/expr.js +18 -0
- package/dist/host-modules/expr.js.map +1 -0
- package/dist/host-modules/fabric.d.ts +46 -0
- package/dist/host-modules/fabric.d.ts.map +1 -0
- package/dist/host-modules/fabric.js +178 -0
- package/dist/host-modules/fabric.js.map +1 -0
- package/dist/host-modules/html.d.ts +51 -0
- package/dist/host-modules/html.d.ts.map +1 -0
- package/dist/host-modules/html.js +198 -0
- package/dist/host-modules/html.js.map +1 -0
- package/dist/host-modules/ics.d.ts +9 -0
- package/dist/host-modules/ics.d.ts.map +1 -0
- package/dist/host-modules/ics.js +35 -0
- package/dist/host-modules/ics.js.map +1 -0
- package/dist/host-modules/limits.d.ts +41 -0
- package/dist/host-modules/limits.d.ts.map +1 -0
- package/dist/host-modules/limits.js +76 -0
- package/dist/host-modules/limits.js.map +1 -0
- package/dist/host-modules/mammoth.d.ts +11 -0
- package/dist/host-modules/mammoth.d.ts.map +1 -0
- package/dist/host-modules/mammoth.js +29 -0
- package/dist/host-modules/mammoth.js.map +1 -0
- package/dist/host-modules/notion.d.ts +45 -0
- package/dist/host-modules/notion.d.ts.map +1 -0
- package/dist/host-modules/notion.js +128 -0
- package/dist/host-modules/notion.js.map +1 -0
- package/dist/host-modules/ocr.d.ts +25 -0
- package/dist/host-modules/ocr.d.ts.map +1 -0
- package/dist/host-modules/ocr.js +74 -0
- package/dist/host-modules/ocr.js.map +1 -0
- package/dist/host-modules/pdf.d.ts +21 -0
- package/dist/host-modules/pdf.d.ts.map +1 -0
- package/dist/host-modules/pdf.js +53 -0
- package/dist/host-modules/pdf.js.map +1 -0
- package/dist/host-modules/pdflib.d.ts +17 -0
- package/dist/host-modules/pdflib.d.ts.map +1 -0
- package/dist/host-modules/pdflib.js +138 -0
- package/dist/host-modules/pdflib.js.map +1 -0
- package/dist/host-modules/pptx.d.ts +19 -0
- package/dist/host-modules/pptx.d.ts.map +1 -0
- package/dist/host-modules/pptx.js +67 -0
- package/dist/host-modules/pptx.js.map +1 -0
- package/dist/host-modules/pptxgen.d.ts +13 -0
- package/dist/host-modules/pptxgen.d.ts.map +1 -0
- package/dist/host-modules/pptxgen.js +98 -0
- package/dist/host-modules/pptxgen.js.map +1 -0
- package/dist/host-modules/prepared-request.d.ts +41 -0
- package/dist/host-modules/prepared-request.d.ts.map +1 -0
- package/dist/host-modules/prepared-request.js +104 -0
- package/dist/host-modules/prepared-request.js.map +1 -0
- package/dist/host-modules/registry.d.ts +31 -0
- package/dist/host-modules/registry.d.ts.map +1 -0
- package/dist/host-modules/registry.js +193 -0
- package/dist/host-modules/registry.js.map +1 -0
- package/dist/host-modules/subtitle.d.ts +15 -0
- package/dist/host-modules/subtitle.d.ts.map +1 -0
- package/dist/host-modules/subtitle.js +45 -0
- package/dist/host-modules/subtitle.js.map +1 -0
- package/dist/host-modules/supabase.d.ts +42 -0
- package/dist/host-modules/supabase.d.ts.map +1 -0
- package/dist/host-modules/supabase.js +141 -0
- package/dist/host-modules/supabase.js.map +1 -0
- package/dist/host-modules/tfjs.d.ts +42 -0
- package/dist/host-modules/tfjs.d.ts.map +1 -0
- package/dist/host-modules/tfjs.js +186 -0
- package/dist/host-modules/tfjs.js.map +1 -0
- package/dist/host-modules/tokens.d.ts +17 -0
- package/dist/host-modules/tokens.d.ts.map +1 -0
- package/dist/host-modules/tokens.js +74 -0
- package/dist/host-modules/tokens.js.map +1 -0
- package/dist/host-modules/twilio.d.ts +34 -0
- package/dist/host-modules/twilio.d.ts.map +1 -0
- package/dist/host-modules/twilio.js +67 -0
- package/dist/host-modules/twilio.js.map +1 -0
- package/dist/host-modules/xlsx.d.ts +26 -0
- package/dist/host-modules/xlsx.d.ts.map +1 -0
- package/dist/host-modules/xlsx.js +323 -0
- package/dist/host-modules/xlsx.js.map +1 -0
- package/dist/host-modules/xml.d.ts +23 -0
- package/dist/host-modules/xml.d.ts.map +1 -0
- package/dist/host-modules/xml.js +38 -0
- package/dist/host-modules/xml.js.map +1 -0
- package/dist/host-modules/zip.d.ts +24 -0
- package/dist/host-modules/zip.d.ts.map +1 -0
- package/dist/host-modules/zip.js +70 -0
- package/dist/host-modules/zip.js.map +1 -0
- package/dist/index.d.ts +197 -60
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +153 -60
- package/dist/index.js.map +1 -1
- package/dist/js-sandbox-worker/host.d.ts +136 -0
- package/dist/js-sandbox-worker/host.d.ts.map +1 -0
- package/dist/js-sandbox-worker/host.js +482 -0
- package/dist/js-sandbox-worker/host.js.map +1 -0
- package/dist/js-sandbox-worker/interpreter.d.ts +276 -0
- package/dist/js-sandbox-worker/interpreter.d.ts.map +1 -0
- package/dist/js-sandbox-worker/interpreter.js +1201 -0
- package/dist/js-sandbox-worker/interpreter.js.map +1 -0
- package/dist/js-sandbox-worker/protocol.d.ts +168 -0
- package/dist/js-sandbox-worker/protocol.d.ts.map +1 -0
- package/dist/js-sandbox-worker/protocol.js +217 -0
- package/dist/js-sandbox-worker/protocol.js.map +1 -0
- package/dist/js-sandbox-worker/worker-entry.d.ts +26 -0
- package/dist/js-sandbox-worker/worker-entry.d.ts.map +1 -0
- package/dist/js-sandbox-worker/worker-entry.js +307 -0
- package/dist/js-sandbox-worker/worker-entry.js.map +1 -0
- package/dist/js-sandbox.d.ts +455 -15
- package/dist/js-sandbox.d.ts.map +1 -1
- package/dist/js-sandbox.js +1961 -309
- package/dist/js-sandbox.js.map +1 -1
- package/dist/js-script-app-runner.d.ts +9 -0
- package/dist/js-script-app-runner.d.ts.map +1 -0
- package/dist/js-script-app-runner.js +49 -0
- package/dist/js-script-app-runner.js.map +1 -0
- package/dist/js-script-sandbox.d.ts +33 -0
- package/dist/js-script-sandbox.d.ts.map +1 -0
- package/dist/js-script-sandbox.js +82 -0
- package/dist/js-script-sandbox.js.map +1 -0
- package/dist/jtbd/friction.d.ts +26 -0
- package/dist/jtbd/friction.d.ts.map +1 -0
- package/dist/jtbd/friction.js +169 -0
- package/dist/jtbd/friction.js.map +1 -0
- package/dist/jtbd/index.d.ts +6 -0
- package/dist/jtbd/index.d.ts.map +1 -0
- package/dist/jtbd/index.js +6 -0
- package/dist/jtbd/index.js.map +1 -0
- package/dist/jtbd/optimize.d.ts +71 -0
- package/dist/jtbd/optimize.d.ts.map +1 -0
- package/dist/jtbd/optimize.js +176 -0
- package/dist/jtbd/optimize.js.map +1 -0
- package/dist/jtbd/registry.d.ts +29 -0
- package/dist/jtbd/registry.d.ts.map +1 -0
- package/dist/jtbd/registry.js +451 -0
- package/dist/jtbd/registry.js.map +1 -0
- package/dist/jtbd/run.d.ts +70 -0
- package/dist/jtbd/run.d.ts.map +1 -0
- package/dist/jtbd/run.js +177 -0
- package/dist/jtbd/run.js.map +1 -0
- package/dist/jtbd/types.d.ts +141 -0
- package/dist/jtbd/types.d.ts.map +1 -0
- package/dist/jtbd/types.js +25 -0
- package/dist/jtbd/types.js.map +1 -0
- package/dist/model-prompting-skills.d.ts +45 -0
- package/dist/model-prompting-skills.d.ts.map +1 -0
- package/dist/model-prompting-skills.js +116 -0
- package/dist/model-prompting-skills.js.map +1 -0
- package/dist/network-guard.d.ts +50 -0
- package/dist/network-guard.d.ts.map +1 -0
- package/dist/network-guard.js +106 -0
- package/dist/network-guard.js.map +1 -0
- package/dist/normalize-model-properties.d.ts +26 -0
- package/dist/normalize-model-properties.d.ts.map +1 -0
- package/dist/normalize-model-properties.js +58 -0
- package/dist/normalize-model-properties.js.map +1 -0
- package/dist/output-format.d.ts +5 -1
- package/dist/output-format.d.ts.map +1 -1
- package/dist/output-format.js.map +1 -1
- package/dist/parallel-task-executor.d.ts +68 -37
- package/dist/parallel-task-executor.d.ts.map +1 -1
- package/dist/parallel-task-executor.js +234 -203
- package/dist/parallel-task-executor.js.map +1 -1
- package/dist/prompts/background-subtask-prompt.d.ts +14 -0
- package/dist/prompts/background-subtask-prompt.d.ts.map +1 -0
- package/dist/prompts/background-subtask-prompt.js +64 -0
- package/dist/prompts/background-subtask-prompt.js.map +1 -0
- package/dist/prompts/product-knowledge.d.ts +3 -0
- package/dist/prompts/product-knowledge.d.ts.map +1 -0
- package/dist/prompts/product-knowledge.js +79 -0
- package/dist/prompts/product-knowledge.js.map +1 -0
- package/dist/prompts/read-only-search-prompt.d.ts +33 -0
- package/dist/prompts/read-only-search-prompt.d.ts.map +1 -0
- package/dist/prompts/read-only-search-prompt.js +109 -0
- package/dist/prompts/read-only-search-prompt.js.map +1 -0
- package/dist/prompts/sandbox-pack-catalog.d.ts +23 -0
- package/dist/prompts/sandbox-pack-catalog.d.ts.map +1 -0
- package/dist/prompts/sandbox-pack-catalog.js +40 -0
- package/dist/prompts/sandbox-pack-catalog.js.map +1 -0
- package/dist/prompts/security-monitor-prompt.d.ts +32 -0
- package/dist/prompts/security-monitor-prompt.d.ts.map +1 -0
- package/dist/prompts/security-monitor-prompt.js +99 -0
- package/dist/prompts/security-monitor-prompt.js.map +1 -0
- package/dist/prompts/workflow-authoring-knowledge.d.ts +77 -0
- package/dist/prompts/workflow-authoring-knowledge.d.ts.map +1 -0
- package/dist/prompts/workflow-authoring-knowledge.js +319 -0
- package/dist/prompts/workflow-authoring-knowledge.js.map +1 -0
- package/dist/run-policy.d.ts +25 -0
- package/dist/run-policy.d.ts.map +1 -0
- package/dist/run-policy.js +54 -0
- package/dist/run-policy.js.map +1 -0
- package/dist/sandbox-av-media.d.ts +33 -0
- package/dist/sandbox-av-media.d.ts.map +1 -0
- package/dist/sandbox-av-media.js +666 -0
- package/dist/sandbox-av-media.js.map +1 -0
- package/dist/sandbox-bootstrap-modules.d.ts +54 -0
- package/dist/sandbox-bootstrap-modules.d.ts.map +1 -0
- package/dist/sandbox-bootstrap-modules.js +104 -0
- package/dist/sandbox-bootstrap-modules.js.map +1 -0
- package/dist/sandbox-bytes.d.ts +43 -0
- package/dist/sandbox-bytes.d.ts.map +1 -0
- package/dist/sandbox-bytes.js +61 -0
- package/dist/sandbox-bytes.js.map +1 -0
- package/dist/sandbox-canvas-api.d.ts +30 -0
- package/dist/sandbox-canvas-api.d.ts.map +1 -0
- package/dist/sandbox-canvas-api.js +81 -0
- package/dist/sandbox-canvas-api.js.map +1 -0
- package/dist/sandbox-constants.d.ts +5 -0
- package/dist/sandbox-constants.d.ts.map +1 -0
- package/dist/sandbox-constants.js +13 -0
- package/dist/sandbox-constants.js.map +1 -0
- package/dist/sandbox-json-transport.d.ts +107 -0
- package/dist/sandbox-json-transport.d.ts.map +1 -0
- package/dist/sandbox-json-transport.js +324 -0
- package/dist/sandbox-json-transport.js.map +1 -0
- package/dist/sandbox-media-handle.d.ts +78 -0
- package/dist/sandbox-media-handle.d.ts.map +1 -0
- package/dist/sandbox-media-handle.js +114 -0
- package/dist/sandbox-media-handle.js.map +1 -0
- package/dist/sandbox-media-ref.d.ts +134 -0
- package/dist/sandbox-media-ref.d.ts.map +1 -0
- package/dist/sandbox-media-ref.js +442 -0
- package/dist/sandbox-media-ref.js.map +1 -0
- package/dist/sandbox-media.d.ts +177 -0
- package/dist/sandbox-media.d.ts.map +1 -0
- package/dist/sandbox-media.js +963 -0
- package/dist/sandbox-media.js.map +1 -0
- package/dist/sandbox-module-fixtures.d.ts +445 -0
- package/dist/sandbox-module-fixtures.d.ts.map +1 -0
- package/dist/sandbox-module-fixtures.js +214 -0
- package/dist/sandbox-module-fixtures.js.map +1 -0
- package/dist/sandbox-toolbelt.d.ts +13 -0
- package/dist/sandbox-toolbelt.d.ts.map +1 -0
- package/dist/sandbox-toolbelt.js +64 -0
- package/dist/sandbox-toolbelt.js.map +1 -0
- package/dist/security-monitor.d.ts +89 -0
- package/dist/security-monitor.d.ts.map +1 -0
- package/dist/security-monitor.js +307 -0
- package/dist/security-monitor.js.map +1 -0
- package/dist/serpapi/catalog.d.ts +101 -0
- package/dist/serpapi/catalog.d.ts.map +1 -0
- package/dist/serpapi/catalog.js +246 -0
- package/dist/serpapi/catalog.js.map +1 -0
- package/dist/serpapi/client.d.ts +81 -0
- package/dist/serpapi/client.d.ts.map +1 -0
- package/dist/serpapi/client.js +228 -0
- package/dist/serpapi/client.js.map +1 -0
- package/dist/serpapi/errors.d.ts +49 -0
- package/dist/serpapi/errors.d.ts.map +1 -0
- package/dist/serpapi/errors.js +64 -0
- package/dist/serpapi/errors.js.map +1 -0
- package/dist/serpapi/normalize.d.ts +58 -0
- package/dist/serpapi/normalize.d.ts.map +1 -0
- package/dist/serpapi/normalize.js +140 -0
- package/dist/serpapi/normalize.js.map +1 -0
- package/dist/skill-prompt.d.ts +27 -0
- package/dist/skill-prompt.d.ts.map +1 -0
- package/dist/skill-prompt.js +61 -0
- package/dist/skill-prompt.js.map +1 -0
- package/dist/step-executor.d.ts +90 -77
- package/dist/step-executor.d.ts.map +1 -1
- package/dist/step-executor.js +384 -690
- package/dist/step-executor.js.map +1 -1
- package/dist/subagent.d.ts +275 -0
- package/dist/subagent.d.ts.map +1 -0
- package/dist/subagent.js +444 -0
- package/dist/subagent.js.map +1 -0
- package/dist/supervisor/prompt.d.ts +12 -0
- package/dist/supervisor/prompt.d.ts.map +1 -0
- package/dist/supervisor/prompt.js +51 -0
- package/dist/supervisor/prompt.js.map +1 -0
- package/dist/supervisor/supervisor-agent.d.ts +72 -0
- package/dist/supervisor/supervisor-agent.d.ts.map +1 -0
- package/dist/supervisor/supervisor-agent.js +185 -0
- package/dist/supervisor/supervisor-agent.js.map +1 -0
- package/dist/supervisor/tools.d.ts +56 -0
- package/dist/supervisor/tools.d.ts.map +1 -0
- package/dist/supervisor/tools.js +83 -0
- package/dist/supervisor/tools.js.map +1 -0
- package/dist/supervisor/verdict-schema.d.ts +18 -0
- package/dist/supervisor/verdict-schema.d.ts.map +1 -0
- package/dist/supervisor/verdict-schema.js +58 -0
- package/dist/supervisor/verdict-schema.js.map +1 -0
- package/dist/system-skills.d.ts +68 -0
- package/dist/system-skills.d.ts.map +1 -0
- package/dist/system-skills.js +168 -0
- package/dist/system-skills.js.map +1 -0
- package/dist/task-executor.d.ts +90 -40
- package/dist/task-executor.d.ts.map +1 -1
- package/dist/task-executor.js +259 -282
- package/dist/task-executor.js.map +1 -1
- package/dist/task-planner.d.ts +18 -12
- package/dist/task-planner.d.ts.map +1 -1
- package/dist/task-planner.js +342 -328
- package/dist/task-planner.js.map +1 -1
- package/dist/timeline-preview/compare.d.ts +27 -0
- package/dist/timeline-preview/compare.d.ts.map +1 -0
- package/dist/timeline-preview/compare.js +71 -0
- package/dist/timeline-preview/compare.js.map +1 -0
- package/dist/timeline-preview/frames.d.ts +167 -0
- package/dist/timeline-preview/frames.d.ts.map +1 -0
- package/dist/timeline-preview/frames.js +646 -0
- package/dist/timeline-preview/frames.js.map +1 -0
- package/dist/timeline-preview/model3d.d.ts +67 -0
- package/dist/timeline-preview/model3d.d.ts.map +1 -0
- package/dist/timeline-preview/model3d.js +165 -0
- package/dist/timeline-preview/model3d.js.map +1 -0
- package/dist/timeline-preview/rasterize.d.ts +33 -0
- package/dist/timeline-preview/rasterize.d.ts.map +1 -0
- package/dist/timeline-preview/rasterize.js +83 -0
- package/dist/timeline-preview/rasterize.js.map +1 -0
- package/dist/timeline-preview/sheet.d.ts +38 -0
- package/dist/timeline-preview/sheet.d.ts.map +1 -0
- package/dist/timeline-preview/sheet.js +72 -0
- package/dist/timeline-preview/sheet.js.map +1 -0
- package/dist/tools/asset-persist.d.ts +29 -0
- package/dist/tools/asset-persist.d.ts.map +1 -0
- package/dist/tools/asset-persist.js +78 -0
- package/dist/tools/asset-persist.js.map +1 -0
- package/dist/tools/base-tool.d.ts +52 -5
- package/dist/tools/base-tool.d.ts.map +1 -1
- package/dist/tools/base-tool.js +180 -3
- package/dist/tools/base-tool.js.map +1 -1
- package/dist/tools/binary-output.d.ts +54 -0
- package/dist/tools/binary-output.d.ts.map +1 -0
- package/dist/tools/binary-output.js +127 -0
- package/dist/tools/binary-output.js.map +1 -0
- package/dist/tools/browser-tools.d.ts +5 -29
- package/dist/tools/browser-tools.d.ts.map +1 -1
- package/dist/tools/browser-tools.js +5 -205
- package/dist/tools/browser-tools.js.map +1 -1
- package/dist/tools/builtin-tools.d.ts +52 -0
- package/dist/tools/builtin-tools.d.ts.map +1 -0
- package/dist/tools/builtin-tools.js +276 -0
- package/dist/tools/builtin-tools.js.map +1 -0
- package/dist/tools/control-tool.d.ts +2 -5
- package/dist/tools/control-tool.d.ts.map +1 -1
- package/dist/tools/control-tool.js +18 -15
- package/dist/tools/control-tool.js.map +1 -1
- package/dist/tools/dataseo-tools.d.ts +34 -32
- package/dist/tools/dataseo-tools.d.ts.map +1 -1
- package/dist/tools/dataseo-tools.js +148 -233
- package/dist/tools/dataseo-tools.js.map +1 -1
- package/dist/tools/external-capability-tools.d.ts +36 -0
- package/dist/tools/external-capability-tools.d.ts.map +1 -0
- package/dist/tools/external-capability-tools.js +41 -0
- package/dist/tools/external-capability-tools.js.map +1 -0
- package/dist/tools/external-mcp-tools.d.ts +139 -0
- package/dist/tools/external-mcp-tools.d.ts.map +1 -0
- package/dist/tools/external-mcp-tools.js +552 -0
- package/dist/tools/external-mcp-tools.js.map +1 -0
- package/dist/tools/finish-step-tool.d.ts +1 -1
- package/dist/tools/finish-step-tool.d.ts.map +1 -1
- package/dist/tools/finish-step-tool.js +3 -3
- package/dist/tools/finish-step-tool.js.map +1 -1
- package/dist/tools/google-tools.d.ts +28 -39
- package/dist/tools/google-tools.d.ts.map +1 -1
- package/dist/tools/google-tools.js +51 -164
- package/dist/tools/google-tools.js.map +1 -1
- package/dist/tools/google-workspace-tools.d.ts +23 -0
- package/dist/tools/google-workspace-tools.d.ts.map +1 -0
- package/dist/tools/google-workspace-tools.js +26 -0
- package/dist/tools/google-workspace-tools.js.map +1 -0
- package/dist/tools/graph-validation-registry.d.ts +33 -0
- package/dist/tools/graph-validation-registry.d.ts.map +1 -0
- package/dist/tools/graph-validation-registry.js +54 -0
- package/dist/tools/graph-validation-registry.js.map +1 -0
- package/dist/tools/http-tools.d.ts +5 -53
- package/dist/tools/http-tools.d.ts.map +1 -1
- package/dist/tools/http-tools.js +5 -177
- package/dist/tools/http-tools.js.map +1 -1
- package/dist/tools/image-injection.d.ts +51 -0
- package/dist/tools/image-injection.d.ts.map +1 -0
- package/dist/tools/image-injection.js +85 -0
- package/dist/tools/image-injection.js.map +1 -0
- package/dist/tools/mcp-tool-support.d.ts +203 -0
- package/dist/tools/mcp-tool-support.d.ts.map +1 -0
- package/dist/tools/mcp-tool-support.js +536 -0
- package/dist/tools/mcp-tool-support.js.map +1 -0
- package/dist/tools/mcp-tools.d.ts +104 -390
- package/dist/tools/mcp-tools.d.ts.map +1 -1
- package/dist/tools/mcp-tools.js +128 -600
- package/dist/tools/mcp-tools.js.map +1 -1
- package/dist/tools/media-tools.d.ts +9 -272
- package/dist/tools/media-tools.d.ts.map +1 -1
- package/dist/tools/media-tools.js +11 -676
- package/dist/tools/media-tools.js.map +1 -1
- package/dist/tools/memory-tools.d.ts +36 -0
- package/dist/tools/memory-tools.d.ts.map +1 -0
- package/dist/tools/memory-tools.js +52 -0
- package/dist/tools/memory-tools.js.map +1 -0
- package/dist/tools/openai-tools.d.ts +28 -68
- package/dist/tools/openai-tools.d.ts.map +1 -1
- package/dist/tools/openai-tools.js +51 -181
- package/dist/tools/openai-tools.js.map +1 -1
- package/dist/tools/plan-builder-tools.d.ts +141 -7
- package/dist/tools/plan-builder-tools.d.ts.map +1 -1
- package/dist/tools/plan-builder-tools.js +159 -86
- package/dist/tools/plan-builder-tools.js.map +1 -1
- package/dist/tools/run-search-tool.d.ts +82 -0
- package/dist/tools/run-search-tool.d.ts.map +1 -0
- package/dist/tools/run-search-tool.js +121 -0
- package/dist/tools/run-search-tool.js.map +1 -0
- package/dist/tools/run-subtask-tool.d.ts +49 -0
- package/dist/tools/run-subtask-tool.d.ts.map +1 -0
- package/dist/tools/run-subtask-tool.js +88 -0
- package/dist/tools/run-subtask-tool.js.map +1 -0
- package/dist/tools/search-tools.d.ts +5 -36
- package/dist/tools/search-tools.d.ts.map +1 -1
- package/dist/tools/search-tools.js +5 -215
- package/dist/tools/search-tools.js.map +1 -1
- package/dist/tools/serp-providers/apify-provider.d.ts +18 -0
- package/dist/tools/serp-providers/apify-provider.d.ts.map +1 -0
- package/dist/tools/serp-providers/apify-provider.js +93 -0
- package/dist/tools/serp-providers/apify-provider.js.map +1 -0
- package/dist/tools/serp-providers/brave-provider.d.ts +34 -0
- package/dist/tools/serp-providers/brave-provider.d.ts.map +1 -0
- package/dist/tools/serp-providers/brave-provider.js +86 -0
- package/dist/tools/serp-providers/brave-provider.js.map +1 -0
- package/dist/tools/serp-providers/dataforseo-provider.d.ts +14 -1
- package/dist/tools/serp-providers/dataforseo-provider.d.ts.map +1 -1
- package/dist/tools/serp-providers/dataforseo-provider.js +0 -9
- package/dist/tools/serp-providers/dataforseo-provider.js.map +1 -1
- package/dist/tools/serp-providers/gemini-provider.d.ts +45 -0
- package/dist/tools/serp-providers/gemini-provider.d.ts.map +1 -0
- package/dist/tools/serp-providers/gemini-provider.js +148 -0
- package/dist/tools/serp-providers/gemini-provider.js.map +1 -0
- package/dist/tools/serp-providers/index.d.ts +61 -0
- package/dist/tools/serp-providers/index.d.ts.map +1 -1
- package/dist/tools/serp-providers/index.js +119 -3
- package/dist/tools/serp-providers/index.js.map +1 -1
- package/dist/tools/serp-providers/openai-provider.d.ts +58 -0
- package/dist/tools/serp-providers/openai-provider.d.ts.map +1 -0
- package/dist/tools/serp-providers/openai-provider.js +113 -0
- package/dist/tools/serp-providers/openai-provider.js.map +1 -0
- package/dist/tools/serp-providers/serpapi-provider.d.ts +9 -5
- package/dist/tools/serp-providers/serpapi-provider.d.ts.map +1 -1
- package/dist/tools/serp-providers/serpapi-provider.js +26 -44
- package/dist/tools/serp-providers/serpapi-provider.js.map +1 -1
- package/dist/tools/serp-tool-factory.d.ts +27 -0
- package/dist/tools/serp-tool-factory.d.ts.map +1 -0
- package/dist/tools/serp-tool-factory.js +56 -0
- package/dist/tools/serp-tool-factory.js.map +1 -0
- package/dist/tools/shared-tools.d.ts +33 -0
- package/dist/tools/shared-tools.d.ts.map +1 -0
- package/dist/tools/shared-tools.js +39 -0
- package/dist/tools/shared-tools.js.map +1 -0
- package/dist/tools/start-subtask-tool.d.ts +51 -0
- package/dist/tools/start-subtask-tool.d.ts.map +1 -0
- package/dist/tools/start-subtask-tool.js +189 -0
- package/dist/tools/start-subtask-tool.js.map +1 -0
- package/dist/tools/submit-code-tool.d.ts +159 -0
- package/dist/tools/submit-code-tool.d.ts.map +1 -0
- package/dist/tools/submit-code-tool.js +209 -0
- package/dist/tools/submit-code-tool.js.map +1 -0
- package/dist/tools/subtask-fields.d.ts +11 -0
- package/dist/tools/subtask-fields.d.ts.map +1 -0
- package/dist/tools/subtask-fields.js +11 -0
- package/dist/tools/subtask-fields.js.map +1 -0
- package/dist/tools/todo-tools.d.ts +15 -0
- package/dist/tools/todo-tools.d.ts.map +1 -0
- package/dist/tools/todo-tools.js +15 -0
- package/dist/tools/todo-tools.js.map +1 -0
- package/dist/tools/tool-permissions.d.ts +40 -0
- package/dist/tools/tool-permissions.d.ts.map +1 -0
- package/dist/tools/tool-permissions.js +52 -0
- package/dist/tools/tool-permissions.js.map +1 -0
- package/dist/tools/tool-search.d.ts +39 -0
- package/dist/tools/tool-search.d.ts.map +1 -0
- package/dist/tools/tool-search.js +108 -0
- package/dist/tools/tool-search.js.map +1 -0
- package/dist/tools/vector-tool-support.d.ts +15 -0
- package/dist/tools/vector-tool-support.d.ts.map +1 -0
- package/dist/tools/vector-tool-support.js +133 -0
- package/dist/tools/vector-tool-support.js.map +1 -0
- package/dist/tools/vector-tools.d.ts +13 -220
- package/dist/tools/vector-tools.d.ts.map +1 -1
- package/dist/tools/vector-tools.js +7 -578
- package/dist/tools/vector-tools.js.map +1 -1
- package/dist/tools/wait-subtasks-tool.d.ts +27 -0
- package/dist/tools/wait-subtasks-tool.d.ts.map +1 -0
- package/dist/tools/wait-subtasks-tool.js +66 -0
- package/dist/tools/wait-subtasks-tool.js.map +1 -0
- package/dist/tsconfig.tests.tmp.tsbuildinfo +1 -0
- package/dist/types.d.ts +16 -31
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +8 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/dag-scheduler.d.ts +85 -0
- package/dist/utils/dag-scheduler.d.ts.map +1 -0
- package/dist/utils/dag-scheduler.js +180 -0
- package/dist/utils/dag-scheduler.js.map +1 -0
- package/dist/utils/json-parser.d.ts +32 -1
- package/dist/utils/json-parser.d.ts.map +1 -1
- package/dist/utils/json-parser.js +145 -10
- package/dist/utils/json-parser.js.map +1 -1
- package/dist/utils/json-schema-validate.d.ts +29 -0
- package/dist/utils/json-schema-validate.d.ts.map +1 -0
- package/dist/utils/json-schema-validate.js +228 -0
- package/dist/utils/json-schema-validate.js.map +1 -0
- package/dist/utils/link-abort.d.ts +13 -0
- package/dist/utils/link-abort.d.ts.map +1 -0
- package/dist/utils/link-abort.js +23 -0
- package/dist/utils/link-abort.js.map +1 -0
- package/dist/utils/merge-generators.d.ts +58 -0
- package/dist/utils/merge-generators.d.ts.map +1 -0
- package/dist/utils/merge-generators.js +148 -0
- package/dist/utils/merge-generators.js.map +1 -0
- package/dist/utils/remove-base64-images.d.ts +0 -5
- package/dist/utils/remove-base64-images.d.ts.map +1 -1
- package/dist/utils/remove-base64-images.js.map +1 -1
- package/dist/utils/step-failure.d.ts +20 -0
- package/dist/utils/step-failure.d.ts.map +1 -0
- package/dist/utils/step-failure.js +43 -0
- package/dist/utils/step-failure.js.map +1 -0
- package/dist/utils/think-tags.d.ts +16 -0
- package/dist/utils/think-tags.d.ts.map +1 -0
- package/dist/utils/think-tags.js +23 -0
- package/dist/utils/think-tags.js.map +1 -0
- package/dist/utils/type-guards.d.ts +26 -0
- package/dist/utils/type-guards.d.ts.map +1 -0
- package/dist/utils/type-guards.js +44 -0
- package/dist/utils/type-guards.js.map +1 -0
- package/dist/utils/ui-event-buffer.d.ts +18 -0
- package/dist/utils/ui-event-buffer.d.ts.map +1 -0
- package/dist/utils/ui-event-buffer.js +18 -0
- package/dist/utils/ui-event-buffer.js.map +1 -0
- package/dist/utils/wrap-generators-parallel.d.ts +0 -5
- package/dist/utils/wrap-generators-parallel.d.ts.map +1 -1
- package/dist/utils/wrap-generators-parallel.js +3 -6
- package/dist/utils/wrap-generators-parallel.js.map +1 -1
- package/dist/wasm-sandbox/host.d.ts +106 -0
- package/dist/wasm-sandbox/host.d.ts.map +1 -0
- package/dist/wasm-sandbox/host.js +409 -0
- package/dist/wasm-sandbox/host.js.map +1 -0
- package/dist/wasm-sandbox/workers.d.ts +43 -0
- package/dist/wasm-sandbox/workers.d.ts.map +1 -0
- package/dist/wasm-sandbox/workers.js +150 -0
- package/dist/wasm-sandbox/workers.js.map +1 -0
- package/dist/workspace-paths.d.ts +40 -0
- package/dist/workspace-paths.d.ts.map +1 -0
- package/dist/workspace-paths.js +102 -0
- package/dist/workspace-paths.js.map +1 -0
- package/dist/yt-dlp-gate.d.ts +19 -0
- package/dist/yt-dlp-gate.d.ts.map +1 -0
- package/dist/yt-dlp-gate.js +22 -0
- package/dist/yt-dlp-gate.js.map +1 -0
- package/package.json +112 -14
- package/dist/agent-executor.d.ts +0 -62
- package/dist/agent-executor.d.ts.map +0 -1
- package/dist/agent-executor.js +0 -324
- package/dist/agent-executor.js.map +0 -1
- package/dist/agent-step-executor.d.ts +0 -28
- package/dist/agent-step-executor.d.ts.map +0 -1
- package/dist/agent-step-executor.js +0 -99
- package/dist/agent-step-executor.js.map +0 -1
- package/dist/agent-workflow-runner.d.ts +0 -31
- package/dist/agent-workflow-runner.d.ts.map +0 -1
- package/dist/agent-workflow-runner.js +0 -124
- package/dist/agent-workflow-runner.js.map +0 -1
- package/dist/agent.d.ts +0 -115
- package/dist/agent.d.ts.map +0 -1
- package/dist/agent.js +0 -587
- package/dist/agent.js.map +0 -1
- package/dist/base-agent.d.ts +0 -42
- package/dist/base-agent.d.ts.map +0 -1
- package/dist/base-agent.js +0 -29
- package/dist/base-agent.js.map +0 -1
- package/dist/graph-planner.d.ts +0 -56
- package/dist/graph-planner.d.ts.map +0 -1
- package/dist/graph-planner.js +0 -311
- package/dist/graph-planner.js.map +0 -1
- package/dist/multi-mode-agent.d.ts +0 -86
- package/dist/multi-mode-agent.d.ts.map +0 -1
- package/dist/multi-mode-agent.js +0 -476
- package/dist/multi-mode-agent.js.map +0 -1
- package/dist/prompts/graph-planner-prompt.d.ts +0 -48
- package/dist/prompts/graph-planner-prompt.d.ts.map +0 -1
- package/dist/prompts/graph-planner-prompt.js +0 -180
- package/dist/prompts/graph-planner-prompt.js.map +0 -1
- package/dist/reject-agentic-provider.d.ts +0 -21
- package/dist/reject-agentic-provider.d.ts.map +0 -1
- package/dist/reject-agentic-provider.js +0 -32
- package/dist/reject-agentic-provider.js.map +0 -1
- package/dist/simple-agent.d.ts +0 -29
- package/dist/simple-agent.d.ts.map +0 -1
- package/dist/simple-agent.js +0 -54
- package/dist/simple-agent.js.map +0 -1
- package/dist/sub-agent-planner.d.ts +0 -33
- package/dist/sub-agent-planner.d.ts.map +0 -1
- package/dist/sub-agent-planner.js +0 -203
- package/dist/sub-agent-planner.js.map +0 -1
- package/dist/team/db-task-board.d.ts +0 -54
- package/dist/team/db-task-board.d.ts.map +0 -1
- package/dist/team/db-task-board.js +0 -361
- package/dist/team/db-task-board.js.map +0 -1
- package/dist/team/edge-message-bus.d.ts +0 -51
- package/dist/team/edge-message-bus.d.ts.map +0 -1
- package/dist/team/edge-message-bus.js +0 -169
- package/dist/team/edge-message-bus.js.map +0 -1
- package/dist/team/edge-task-board.d.ts +0 -77
- package/dist/team/edge-task-board.d.ts.map +0 -1
- package/dist/team/edge-task-board.js +0 -140
- package/dist/team/edge-task-board.js.map +0 -1
- package/dist/team/index.d.ts +0 -16
- package/dist/team/index.d.ts.map +0 -1
- package/dist/team/index.js +0 -17
- package/dist/team/index.js.map +0 -1
- package/dist/team/message-bus.d.ts +0 -58
- package/dist/team/message-bus.d.ts.map +0 -1
- package/dist/team/message-bus.js +0 -151
- package/dist/team/message-bus.js.map +0 -1
- package/dist/team/task-board.d.ts +0 -106
- package/dist/team/task-board.d.ts.map +0 -1
- package/dist/team/task-board.js +0 -370
- package/dist/team/task-board.js.map +0 -1
- package/dist/team/team-executor.d.ts +0 -72
- package/dist/team/team-executor.d.ts.map +0 -1
- package/dist/team/team-executor.js +0 -466
- package/dist/team/team-executor.js.map +0 -1
- package/dist/team/team-tools.d.ts +0 -252
- package/dist/team/team-tools.d.ts.map +0 -1
- package/dist/team/team-tools.js +0 -412
- package/dist/team/team-tools.js.map +0 -1
- package/dist/team/types.d.ts +0 -198
- package/dist/team/types.d.ts.map +0 -1
- package/dist/team/types.js +0 -8
- package/dist/team/types.js.map +0 -1
- package/dist/tools/add-edge-tool.d.ts +0 -18
- package/dist/tools/add-edge-tool.d.ts.map +0 -1
- package/dist/tools/add-edge-tool.js +0 -92
- package/dist/tools/add-edge-tool.js.map +0 -1
- package/dist/tools/add-node-tool.d.ts +0 -22
- package/dist/tools/add-node-tool.d.ts.map +0 -1
- package/dist/tools/add-node-tool.js +0 -128
- package/dist/tools/add-node-tool.js.map +0 -1
- package/dist/tools/asset-tools.d.ts +0 -58
- package/dist/tools/asset-tools.d.ts.map +0 -1
- package/dist/tools/asset-tools.js +0 -191
- package/dist/tools/asset-tools.js.map +0 -1
- package/dist/tools/calculator-tool.d.ts +0 -24
- package/dist/tools/calculator-tool.d.ts.map +0 -1
- package/dist/tools/calculator-tool.js +0 -64
- package/dist/tools/calculator-tool.js.map +0 -1
- package/dist/tools/claude-code-tools.d.ts +0 -96
- package/dist/tools/claude-code-tools.d.ts.map +0 -1
- package/dist/tools/claude-code-tools.js +0 -463
- package/dist/tools/claude-code-tools.js.map +0 -1
- package/dist/tools/code-tools.d.ts +0 -26
- package/dist/tools/code-tools.d.ts.map +0 -1
- package/dist/tools/code-tools.js +0 -82
- package/dist/tools/code-tools.js.map +0 -1
- package/dist/tools/create-plan-tool.d.ts +0 -29
- package/dist/tools/create-plan-tool.d.ts.map +0 -1
- package/dist/tools/create-plan-tool.js +0 -355
- package/dist/tools/create-plan-tool.js.map +0 -1
- package/dist/tools/create-task-tool.d.ts +0 -28
- package/dist/tools/create-task-tool.d.ts.map +0 -1
- package/dist/tools/create-task-tool.js +0 -254
- package/dist/tools/create-task-tool.js.map +0 -1
- package/dist/tools/email-tools.d.ts +0 -76
- package/dist/tools/email-tools.d.ts.map +0 -1
- package/dist/tools/email-tools.js +0 -259
- package/dist/tools/email-tools.js.map +0 -1
- package/dist/tools/filesystem-tools.d.ts +0 -77
- package/dist/tools/filesystem-tools.d.ts.map +0 -1
- package/dist/tools/filesystem-tools.js +0 -334
- package/dist/tools/filesystem-tools.js.map +0 -1
- package/dist/tools/find-model-tool.d.ts +0 -25
- package/dist/tools/find-model-tool.d.ts.map +0 -1
- package/dist/tools/find-model-tool.js +0 -236
- package/dist/tools/find-model-tool.js.map +0 -1
- package/dist/tools/finish-graph-tool.d.ts +0 -23
- package/dist/tools/finish-graph-tool.d.ts.map +0 -1
- package/dist/tools/finish-graph-tool.js +0 -46
- package/dist/tools/finish-graph-tool.js.map +0 -1
- package/dist/tools/js-code-tool.d.ts +0 -30
- package/dist/tools/js-code-tool.d.ts.map +0 -1
- package/dist/tools/js-code-tool.js +0 -98
- package/dist/tools/js-code-tool.js.map +0 -1
- package/dist/tools/local-get-node-info-tool.d.ts +0 -19
- package/dist/tools/local-get-node-info-tool.d.ts.map +0 -1
- package/dist/tools/local-get-node-info-tool.js +0 -75
- package/dist/tools/local-get-node-info-tool.js.map +0 -1
- package/dist/tools/local-list-nodes-tool.d.ts +0 -19
- package/dist/tools/local-list-nodes-tool.d.ts.map +0 -1
- package/dist/tools/local-list-nodes-tool.js +0 -69
- package/dist/tools/local-list-nodes-tool.js.map +0 -1
- package/dist/tools/local-search-nodes-tool.d.ts +0 -21
- package/dist/tools/local-search-nodes-tool.d.ts.map +0 -1
- package/dist/tools/local-search-nodes-tool.js +0 -111
- package/dist/tools/local-search-nodes-tool.js.map +0 -1
- package/dist/tools/math-tools.d.ts +0 -156
- package/dist/tools/math-tools.d.ts.map +0 -1
- package/dist/tools/math-tools.js +0 -422
- package/dist/tools/math-tools.js.map +0 -1
- package/dist/tools/model-tools.d.ts +0 -25
- package/dist/tools/model-tools.d.ts.map +0 -1
- package/dist/tools/model-tools.js +0 -48
- package/dist/tools/model-tools.js.map +0 -1
- package/dist/tools/pdf-tools.d.ts +0 -152
- package/dist/tools/pdf-tools.d.ts.map +0 -1
- package/dist/tools/pdf-tools.js +0 -339
- package/dist/tools/pdf-tools.js.map +0 -1
- package/dist/tools/tool-registry.d.ts +0 -9
- package/dist/tools/tool-registry.d.ts.map +0 -1
- package/dist/tools/tool-registry.js +0 -17
- package/dist/tools/tool-registry.js.map +0 -1
- package/dist/tools/workspace-tools.d.ts +0 -58
- package/dist/tools/workspace-tools.d.ts.map +0 -1
- package/dist/tools/workspace-tools.js +0 -152
- package/dist/tools/workspace-tools.js.map +0 -1
|
@@ -0,0 +1,2217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `media` capability module — provider-backed generation, plus the vision
|
|
3
|
+
* judges that grade what it produced.
|
|
4
|
+
*
|
|
5
|
+
* These capabilities replace the generation tools in `../tools/media-tools.ts`
|
|
6
|
+
* and the judging tools in `../tools/creative-critique-tools.ts`. Wire names,
|
|
7
|
+
* descriptions and schemas are unchanged; `getAllMcpTools` builds them through
|
|
8
|
+
* `toolFromCapability`.
|
|
9
|
+
*
|
|
10
|
+
* Every generation capability is a thin wrapper around
|
|
11
|
+
* `ProcessingContext.runProviderPrediction` (or `streamProviderPrediction`
|
|
12
|
+
* where the capability requires it), so it dispatches to whichever
|
|
13
|
+
* `BaseProvider` the id names and needs nothing on the run beyond its context.
|
|
14
|
+
*
|
|
15
|
+
* Outputs are saved as assets when the context exposes a `createAsset` model
|
|
16
|
+
* interface, and fall back to the caller-supplied `output_file` under the
|
|
17
|
+
* workspace when it does not.
|
|
18
|
+
*
|
|
19
|
+
* Design: docs/tool-class-retirement-design.md § Migration.
|
|
20
|
+
*/
|
|
21
|
+
import { Buffer } from "node:buffer";
|
|
22
|
+
import { randomInt, randomUUID } from "node:crypto";
|
|
23
|
+
import { mkdir, readFile } from "node:fs/promises";
|
|
24
|
+
import path from "node:path";
|
|
25
|
+
import { loadMediaRefBytes } from "@nodetool-ai/runtime";
|
|
26
|
+
import { getMaxLocalUploadBytes } from "@nodetool-ai/storage";
|
|
27
|
+
import { backgroundGenerationLimitError, startBackgroundGeneration } from "./background-generation.js";
|
|
28
|
+
import { HostBinaryMissingError, clampTimeoutSeconds, mimeFromFilename, runHostBinary } from "../host-binaries.js";
|
|
29
|
+
import { MAX_DOWNLOAD_BYTES, buildYtDlpArgv, confineArgvToWorkspace, hardenFfmpegArgv, refuseFlagLikeValue } from "../host-binary-guard.js";
|
|
30
|
+
import { assertFetchUrlAllowed, assertResolvedHostAllowed } from "../network-guard.js";
|
|
31
|
+
import { encodeBase64 as encodeMediaBase64 } from "../sandbox-bytes.js";
|
|
32
|
+
import { imagePixelSize, sniffImageFormat } from "../sandbox-media.js";
|
|
33
|
+
import { DEFAULT_MIME, MAX_MEDIA_REF_BYTES, filesystemPathForUri, mimeForRef } from "../sandbox-media-ref.js";
|
|
34
|
+
import { MIME_TO_EXT, inferImageMime, persistOutput } from "../tools/asset-persist.js";
|
|
35
|
+
import { persistBinaryOutput } from "../tools/binary-output.js";
|
|
36
|
+
import { extractJSON, extractJSONAllowingTruncation } from "../utils/json-parser.js";
|
|
37
|
+
import { isYtDlpEnabled } from "../yt-dlp-gate.js";
|
|
38
|
+
import { isFunction, isNonBlankString, isNonEmptyString, isObjectLike, isRecord, isString } from "../utils/type-guards.js";
|
|
39
|
+
import { generateTextSpec, generateImageSpec, editImageSpec, segmentImageSpec, generateVideoSpec, animateImageSpec, videoFromReferencesSpec, generateSpeechSpec, generateMusicSpec, transcribeAudioSpec, embedTextSpec, readMediaBytesSpec, critiqueImageSpec, compareImagesSpec, scoreImageAdherenceSpec, understandVideoSpec, ffmpegSpec, ffprobeSpec, ytDlpSpec, DEFAULT_UNDERSTAND_VIDEO_TOKENS, DEFAULT_VIDEO_PROMPT, MAX_COMPARE_IMAGES, MAX_UNDERSTAND_VIDEO_TOKENS } from "./media.specs.js";
|
|
40
|
+
const MAX_INLINE_TEXT_PREVIEW = 500;
|
|
41
|
+
const MAX_ADHERENCE_QUESTIONS = 12;
|
|
42
|
+
const JUDGE_MAX_TOKENS = 1500;
|
|
43
|
+
const generateText = {
|
|
44
|
+
spec: generateTextSpec,
|
|
45
|
+
impl: async (run, params) => {
|
|
46
|
+
const m = parseModelArgs(params);
|
|
47
|
+
if ("error" in m)
|
|
48
|
+
return m;
|
|
49
|
+
const prompt = params["prompt"];
|
|
50
|
+
if (!isNonEmptyString(prompt))
|
|
51
|
+
return { error: "prompt is required" };
|
|
52
|
+
const imageValues = params["images"];
|
|
53
|
+
if (imageValues !== undefined && !Array.isArray(imageValues)) {
|
|
54
|
+
return { error: "images must be an array of strings" };
|
|
55
|
+
}
|
|
56
|
+
const images = (imageValues ?? []).filter(isNonEmptyString);
|
|
57
|
+
if (images.length !== (imageValues ?? []).length) {
|
|
58
|
+
return { error: "images must contain only non-empty strings" };
|
|
59
|
+
}
|
|
60
|
+
const content = [
|
|
61
|
+
...images.map(imagePart),
|
|
62
|
+
textPart(prompt)
|
|
63
|
+
];
|
|
64
|
+
const messages = [];
|
|
65
|
+
const system = params["system"];
|
|
66
|
+
if (isNonEmptyString(system)) {
|
|
67
|
+
messages.push({ role: "system", content: system });
|
|
68
|
+
}
|
|
69
|
+
messages.push({ role: "user", content });
|
|
70
|
+
const maxTokens = Math.max(1, Math.min(16384, Number(params["max_tokens"]) || 2048));
|
|
71
|
+
try {
|
|
72
|
+
const result = (await run.context.runProviderPrediction({
|
|
73
|
+
provider: m.provider,
|
|
74
|
+
capability: "generate_message",
|
|
75
|
+
model: m.model,
|
|
76
|
+
params: {
|
|
77
|
+
messages,
|
|
78
|
+
max_tokens: maxTokens,
|
|
79
|
+
temperature: typeof params["temperature"] === "number"
|
|
80
|
+
? params["temperature"]
|
|
81
|
+
: 0
|
|
82
|
+
}
|
|
83
|
+
}));
|
|
84
|
+
return {
|
|
85
|
+
type: "text",
|
|
86
|
+
provider: m.provider,
|
|
87
|
+
model: m.model,
|
|
88
|
+
text: messageText(result)
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
return predictionError("generate_message", m, error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
function readModelId(value) {
|
|
97
|
+
return isNonEmptyString(value) ? value : undefined;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Read a provider+model from the shapes find_model actually returns: a hit
|
|
101
|
+
* (`provider` + `model_id` + `ref`), its `.ref` (`provider` + `id`), or the
|
|
102
|
+
* documented `{provider, model}` pair. Nested `model` objects win over the
|
|
103
|
+
* top-level pair so `generate_video({prompt, model: hit.ref})` works.
|
|
104
|
+
*/
|
|
105
|
+
function modelFromRecord(value) {
|
|
106
|
+
if (!isRecord(value))
|
|
107
|
+
return null;
|
|
108
|
+
if (isRecord(value.ref)) {
|
|
109
|
+
const fromRef = modelFromRecord(value.ref);
|
|
110
|
+
if (fromRef !== null)
|
|
111
|
+
return fromRef;
|
|
112
|
+
}
|
|
113
|
+
const provider = readModelId(value.provider);
|
|
114
|
+
const id = readModelId(value.model_id) ??
|
|
115
|
+
(isNonEmptyString(value.model) ? value.model : undefined) ??
|
|
116
|
+
readModelId(value.id);
|
|
117
|
+
if (provider !== undefined && id !== undefined) {
|
|
118
|
+
return { provider, model: id };
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* A provider rejection, with the model that was called in it.
|
|
124
|
+
*
|
|
125
|
+
* "text_to_video failed: Unprocessable Entity" told a live session nothing:
|
|
126
|
+
* the model it had picked was an image-to-video endpoint, and the message
|
|
127
|
+
* named neither the model nor the way out. `find_model` now filters by
|
|
128
|
+
* direction, and when a provider still refuses, the error says which model to
|
|
129
|
+
* re-pick.
|
|
130
|
+
*/
|
|
131
|
+
function predictionError(capability, m, e) {
|
|
132
|
+
const detail = e instanceof Error ? e.message : String(e);
|
|
133
|
+
return {
|
|
134
|
+
error: `${capability} failed for ${m.provider}:${m.model} — ${detail}. ` +
|
|
135
|
+
`If the model does not do ${capability}, pick another with ` +
|
|
136
|
+
`find_model({capability: "${capability}"}).`
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function parseModelArgs(params) {
|
|
140
|
+
const fromModel = modelFromRecord(params.model);
|
|
141
|
+
if (fromModel !== null)
|
|
142
|
+
return fromModel;
|
|
143
|
+
if (isRecord(params.model) && isNonEmptyString(params.provider)) {
|
|
144
|
+
const nested = params.model;
|
|
145
|
+
const id = readModelId(nested.model_id) ??
|
|
146
|
+
readModelId(nested.id) ??
|
|
147
|
+
(isNonEmptyString(nested.model) ? nested.model : undefined);
|
|
148
|
+
if (id !== undefined) {
|
|
149
|
+
return { provider: params.provider, model: id };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const fromParams = modelFromRecord(params);
|
|
153
|
+
if (fromParams !== null)
|
|
154
|
+
return fromParams;
|
|
155
|
+
if (isNonEmptyString(params.model) && params.model.includes("/")) {
|
|
156
|
+
const slash = params.model.indexOf("/");
|
|
157
|
+
return {
|
|
158
|
+
provider: params.model.slice(0, slash),
|
|
159
|
+
model: params.model.slice(slash + 1)
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (!isNonEmptyString(params.provider)) {
|
|
163
|
+
return { error: "provider must be a non-empty string (use find_model)" };
|
|
164
|
+
}
|
|
165
|
+
if (!isNonEmptyString(params.model)) {
|
|
166
|
+
return { error: "model must be a non-empty string (use find_model)" };
|
|
167
|
+
}
|
|
168
|
+
return { provider: params.provider, model: params.model };
|
|
169
|
+
}
|
|
170
|
+
async function readWorkspaceOrAssetFile(context, inputFile) {
|
|
171
|
+
// asset:// URIs are the primary handle the generate_* capabilities return (an
|
|
172
|
+
// asset is created with no workspace copy), and the docs advertise asset://
|
|
173
|
+
// sources. Route them through the asset resolver — the workspace treats them
|
|
174
|
+
// as literal keys (asset://id.png → key "asset:/id.png") and fails.
|
|
175
|
+
if (inputFile.startsWith("asset://")) {
|
|
176
|
+
const { bytes } = await context.resolveAssetBytes(inputFile);
|
|
177
|
+
if (!bytes) {
|
|
178
|
+
throw new Error(`Asset not found: ${inputFile}`);
|
|
179
|
+
}
|
|
180
|
+
return bytes;
|
|
181
|
+
}
|
|
182
|
+
// Read through the workspace so a cloud deployment behaves like a local one.
|
|
183
|
+
if (!context.workspace) {
|
|
184
|
+
throw new Error("No workspace configured — cannot read input file.");
|
|
185
|
+
}
|
|
186
|
+
const bytes = await context.workspace.read(inputFile);
|
|
187
|
+
if (!bytes) {
|
|
188
|
+
throw new Error(`Input file not found in workspace: ${inputFile}`);
|
|
189
|
+
}
|
|
190
|
+
return bytes;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* A generation that produced no handle is a failure, not a success.
|
|
194
|
+
*
|
|
195
|
+
* A run whose bytes never became an asset (no asset interface, `createAsset`
|
|
196
|
+
* threw, no workspace to fall back to) used to return `{type, provider, model,
|
|
197
|
+
* bytes, mime_type}` — success-shaped, with `asset_uri` undefined, which an
|
|
198
|
+
* agent printed as "OK undefined" and carried on from. Report what was missing
|
|
199
|
+
* instead.
|
|
200
|
+
*/
|
|
201
|
+
function outputError(capability, m, missing) {
|
|
202
|
+
return {
|
|
203
|
+
error: `${capability} for ${m.provider}:${m.model} returned no usable output — ${missing}.`
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/** The provider's bytes, or null when it produced none. */
|
|
207
|
+
function generatedBytes(result) {
|
|
208
|
+
return result instanceof Uint8Array && result.length > 0 ? result : null;
|
|
209
|
+
}
|
|
210
|
+
/** Whether a persisted output carries a handle the caller can read back. */
|
|
211
|
+
function hasOutputHandle(persisted) {
|
|
212
|
+
return (isNonEmptyString(persisted.asset_uri) || isNonEmptyString(persisted.path));
|
|
213
|
+
}
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
// The generation seam, as the capabilities use it
|
|
216
|
+
// ---------------------------------------------------------------------------
|
|
217
|
+
function toolCallIdOf(params) {
|
|
218
|
+
const id = params["_tool_call_id"];
|
|
219
|
+
return isNonEmptyString(id) ? id : null;
|
|
220
|
+
}
|
|
221
|
+
function outputFileOf(params) {
|
|
222
|
+
return isString(params["output_file"]) ? params["output_file"] : undefined;
|
|
223
|
+
}
|
|
224
|
+
/** The request every media capability hands `runGeneration`. */
|
|
225
|
+
function generationRequest(id, params, spec) {
|
|
226
|
+
const outputFile = outputFileOf(params);
|
|
227
|
+
const persist = {};
|
|
228
|
+
if (outputFile)
|
|
229
|
+
persist.name = path.basename(outputFile);
|
|
230
|
+
if (spec.mime)
|
|
231
|
+
persist.mime = spec.mime;
|
|
232
|
+
return {
|
|
233
|
+
id,
|
|
234
|
+
provider: spec.m.provider,
|
|
235
|
+
capability: spec.capability,
|
|
236
|
+
model: spec.m.model,
|
|
237
|
+
params: spec.params,
|
|
238
|
+
origin: { surface: "capability", tool_call_id: toolCallIdOf(params) },
|
|
239
|
+
persist
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Write the bytes where the caller can read them back: the asset the seam
|
|
244
|
+
* saved when it could, plus a workspace copy when `output_file` was named or
|
|
245
|
+
* no asset exists. `persistOutput` handles the no-asset case as before.
|
|
246
|
+
*/
|
|
247
|
+
async function finishOutput(context, bytes, assets, opts) {
|
|
248
|
+
const first = assets[0];
|
|
249
|
+
if (!first || !isNonEmptyString(first.asset_id)) {
|
|
250
|
+
return persistOutput(context, bytes, opts);
|
|
251
|
+
}
|
|
252
|
+
const result = {
|
|
253
|
+
bytes: bytes.length,
|
|
254
|
+
mime_type: opts.mime,
|
|
255
|
+
asset_id: first.asset_id,
|
|
256
|
+
asset_uri: first.uri,
|
|
257
|
+
url: first.uri
|
|
258
|
+
};
|
|
259
|
+
if (opts.outputFile && context.workspace) {
|
|
260
|
+
try {
|
|
261
|
+
await context.workspace.write(opts.outputFile, bytes, opts.mime);
|
|
262
|
+
result.path = opts.outputFile;
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
// Non-fatal — the asset is the handle.
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return result;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* The asset the seam saved for a generation, read off the registry's settled
|
|
272
|
+
* outcome. The encoded-audio paths return the provider's result rather than
|
|
273
|
+
* the seam's, so this is how a capability learns what was persisted.
|
|
274
|
+
*/
|
|
275
|
+
async function seamAssetFor(id) {
|
|
276
|
+
const { generationRegistry } = await import("@nodetool-ai/runtime");
|
|
277
|
+
const outcome = generationRegistry.outcome(id);
|
|
278
|
+
return outcome?.asset_ids[0] ?? null;
|
|
279
|
+
}
|
|
280
|
+
/** What a `background: true` call answers with. */
|
|
281
|
+
function backgroundReceipt(id, spec) {
|
|
282
|
+
return {
|
|
283
|
+
type: spec.type,
|
|
284
|
+
generation_id: id,
|
|
285
|
+
status: "running",
|
|
286
|
+
background: true,
|
|
287
|
+
provider: spec.m.provider,
|
|
288
|
+
model: spec.m.model,
|
|
289
|
+
capability: spec.capability,
|
|
290
|
+
next: "Call await_generation with this generation_id to collect the asset, or get_generation to check on it."
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Start a generation without waiting for it. The seam records the row and
|
|
295
|
+
* saves the asset whether or not anyone awaits; the count is bounded so a
|
|
296
|
+
* loop cannot open an unbounded number of paid calls.
|
|
297
|
+
*/
|
|
298
|
+
function startMediaBackgroundGeneration(context, req, spec, params) {
|
|
299
|
+
const outputFile = outputFileOf(params);
|
|
300
|
+
const started = startBackgroundGeneration(context, async () => {
|
|
301
|
+
const result = await context.runGeneration(req);
|
|
302
|
+
const bytes = generatedBytes(result.output);
|
|
303
|
+
if (bytes && outputFile && context.workspace) {
|
|
304
|
+
await context.workspace.write(outputFile, bytes, spec.mime ?? inferImageMime(bytes));
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
if (!started) {
|
|
308
|
+
return backgroundGenerationLimitError();
|
|
309
|
+
}
|
|
310
|
+
return backgroundReceipt(req.id ?? "", spec);
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Run one media generation through the seam and answer with the handle:
|
|
314
|
+
* the asset (and workspace path) plus the `generation_id` the `generations`
|
|
315
|
+
* capabilities take.
|
|
316
|
+
*/
|
|
317
|
+
async function runMediaGeneration(run, params, spec) {
|
|
318
|
+
const context = run.context;
|
|
319
|
+
const id = randomUUID();
|
|
320
|
+
const req = generationRequest(id, params, spec);
|
|
321
|
+
if (params["background"] === true) {
|
|
322
|
+
return startMediaBackgroundGeneration(context, req, spec, params);
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
const result = await context.runGeneration(req);
|
|
326
|
+
const bytes = generatedBytes(result.output);
|
|
327
|
+
if (!bytes) {
|
|
328
|
+
return {
|
|
329
|
+
...outputError(spec.capability, spec.m, `the provider returned no ${spec.type} data`),
|
|
330
|
+
generation_id: id
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
const persisted = await finishOutput(context, bytes, result.assets, {
|
|
334
|
+
namePrefix: spec.namePrefix,
|
|
335
|
+
mime: spec.mime ?? inferImageMime(bytes),
|
|
336
|
+
outputFile: outputFileOf(params)
|
|
337
|
+
});
|
|
338
|
+
if (!hasOutputHandle(persisted)) {
|
|
339
|
+
return {
|
|
340
|
+
...outputError(spec.capability, spec.m, `the ${persisted.bytes}-byte result could not be stored (no asset was created and no workspace file was written)`),
|
|
341
|
+
generation_id: id
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
type: spec.type,
|
|
346
|
+
provider: spec.m.provider,
|
|
347
|
+
model: spec.m.model,
|
|
348
|
+
generation_id: id,
|
|
349
|
+
...persisted
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
catch (e) {
|
|
353
|
+
return {
|
|
354
|
+
...predictionError(spec.capability, spec.m, e),
|
|
355
|
+
generation_id: id
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const generateImage = {
|
|
360
|
+
spec: generateImageSpec,
|
|
361
|
+
impl: async (run, params) => {
|
|
362
|
+
const m = parseModelArgs(params);
|
|
363
|
+
if ("error" in m)
|
|
364
|
+
return m;
|
|
365
|
+
const prompt = params["prompt"];
|
|
366
|
+
if (!isNonEmptyString(prompt))
|
|
367
|
+
return { error: "prompt is required" };
|
|
368
|
+
return runMediaGeneration(run, params, {
|
|
369
|
+
capability: "text_to_image",
|
|
370
|
+
m,
|
|
371
|
+
type: "image",
|
|
372
|
+
namePrefix: "generated-image",
|
|
373
|
+
params: {
|
|
374
|
+
prompt,
|
|
375
|
+
negative_prompt: params["negative_prompt"],
|
|
376
|
+
width: params["width"],
|
|
377
|
+
height: params["height"],
|
|
378
|
+
quality: params["quality"]
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
const editImage = {
|
|
384
|
+
spec: editImageSpec,
|
|
385
|
+
impl: async (run, params) => {
|
|
386
|
+
const context = run.context;
|
|
387
|
+
const m = parseModelArgs(params);
|
|
388
|
+
if ("error" in m)
|
|
389
|
+
return m;
|
|
390
|
+
const inputFile = params["input_file"];
|
|
391
|
+
const prompt = params["prompt"];
|
|
392
|
+
if (!isNonEmptyString(inputFile))
|
|
393
|
+
return { error: "input_file is required" };
|
|
394
|
+
if (!isNonEmptyString(prompt))
|
|
395
|
+
return { error: "prompt is required" };
|
|
396
|
+
const referenceFiles = params["reference_files"];
|
|
397
|
+
if (referenceFiles !== undefined && !Array.isArray(referenceFiles))
|
|
398
|
+
return { error: "reference_files must be an array of strings" };
|
|
399
|
+
const references = (referenceFiles ?? []).filter(isNonEmptyString);
|
|
400
|
+
let images;
|
|
401
|
+
try {
|
|
402
|
+
images = await Promise.all([inputFile, ...references].map((file) => readWorkspaceOrAssetFile(context, file)));
|
|
403
|
+
}
|
|
404
|
+
catch (e) {
|
|
405
|
+
return predictionError("image_to_image", m, e);
|
|
406
|
+
}
|
|
407
|
+
return runMediaGeneration(run, params, {
|
|
408
|
+
capability: "image_to_image",
|
|
409
|
+
m,
|
|
410
|
+
type: "image",
|
|
411
|
+
namePrefix: "edited-image",
|
|
412
|
+
params: {
|
|
413
|
+
// `coerceImageList` reads the list; the source image stays first so a
|
|
414
|
+
// provider that treats one input as the canvas and the rest as style
|
|
415
|
+
// references gets them in that order.
|
|
416
|
+
images,
|
|
417
|
+
prompt,
|
|
418
|
+
negative_prompt: params["negative_prompt"],
|
|
419
|
+
target_width: params["target_width"],
|
|
420
|
+
target_height: params["target_height"],
|
|
421
|
+
strength: params["strength"]
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
/** Coerce one `points` entry from the model's arguments. */
|
|
427
|
+
function parseSegmentPoint(value) {
|
|
428
|
+
if (!isRecord(value))
|
|
429
|
+
return null;
|
|
430
|
+
const x = value["x"];
|
|
431
|
+
const y = value["y"];
|
|
432
|
+
if (typeof x !== "number" || typeof y !== "number")
|
|
433
|
+
return null;
|
|
434
|
+
return { x, y, include: value["include"] !== false };
|
|
435
|
+
}
|
|
436
|
+
function parseSegmentBox(value) {
|
|
437
|
+
if (!isRecord(value))
|
|
438
|
+
return null;
|
|
439
|
+
const { x, y, width, height } = value;
|
|
440
|
+
if (typeof x !== "number" ||
|
|
441
|
+
typeof y !== "number" ||
|
|
442
|
+
typeof width !== "number" ||
|
|
443
|
+
typeof height !== "number") {
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
446
|
+
return { x, y, width, height };
|
|
447
|
+
}
|
|
448
|
+
const segmentImage = {
|
|
449
|
+
spec: segmentImageSpec,
|
|
450
|
+
impl: async (run, params) => {
|
|
451
|
+
const context = run.context;
|
|
452
|
+
const m = parseModelArgs(params);
|
|
453
|
+
if ("error" in m)
|
|
454
|
+
return m;
|
|
455
|
+
const inputFile = params["input_file"];
|
|
456
|
+
if (!isNonEmptyString(inputFile))
|
|
457
|
+
return { error: "input_file is required" };
|
|
458
|
+
const rawPoints = params["points"];
|
|
459
|
+
const points = Array.isArray(rawPoints)
|
|
460
|
+
? rawPoints
|
|
461
|
+
.map(parseSegmentPoint)
|
|
462
|
+
.filter((p) => p !== null)
|
|
463
|
+
: [];
|
|
464
|
+
try {
|
|
465
|
+
const image = await readWorkspaceOrAssetFile(context, inputFile);
|
|
466
|
+
const masks = (await context.runProviderPrediction({
|
|
467
|
+
provider: m.provider,
|
|
468
|
+
capability: "segment_image",
|
|
469
|
+
model: m.model,
|
|
470
|
+
params: {
|
|
471
|
+
image,
|
|
472
|
+
prompt: params["prompt"],
|
|
473
|
+
points: points.length > 0 ? points : undefined,
|
|
474
|
+
box: parseSegmentBox(params["box"]) ?? undefined,
|
|
475
|
+
max_masks: params["max_masks"],
|
|
476
|
+
min_confidence: params["min_confidence"]
|
|
477
|
+
}
|
|
478
|
+
}));
|
|
479
|
+
const saved = [];
|
|
480
|
+
for (const [index, found] of masks.entries()) {
|
|
481
|
+
const persisted = await persistOutput(context, found.mask, {
|
|
482
|
+
namePrefix: `segment-mask-${index + 1}`,
|
|
483
|
+
mime: found.mimeType || inferImageMime(found.mask)
|
|
484
|
+
});
|
|
485
|
+
saved.push({
|
|
486
|
+
label: found.label ?? null,
|
|
487
|
+
confidence: found.confidence ?? null,
|
|
488
|
+
box: found.box ?? null,
|
|
489
|
+
width: found.width ?? null,
|
|
490
|
+
height: found.height ?? null,
|
|
491
|
+
...persisted
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
return {
|
|
495
|
+
type: "segmentation",
|
|
496
|
+
provider: m.provider,
|
|
497
|
+
model: m.model,
|
|
498
|
+
// An empty list is the model's answer, not a failure — say so, because
|
|
499
|
+
// a bare `[]` reads as a broken call.
|
|
500
|
+
found: saved.length,
|
|
501
|
+
masks: saved
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
catch (e) {
|
|
505
|
+
return predictionError("segment_image", m, e);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
/**
|
|
510
|
+
* Read a generation parameter under any of the spellings a caller reaches for.
|
|
511
|
+
*
|
|
512
|
+
* The schemas are snake_case, the JS guest API takes an options bag, and the
|
|
513
|
+
* `TextToVideo` node's own property is `duration` — so a build asked for a
|
|
514
|
+
* 15-second clip with `{duration: 15}`, was billed for the model's 5-second
|
|
515
|
+
* default, and had nothing in the result saying the argument had been dropped.
|
|
516
|
+
* A silently ignored parameter on a call that spends money is the expensive
|
|
517
|
+
* kind of typo, and every one of these spellings means one thing.
|
|
518
|
+
*/
|
|
519
|
+
function aliased(params, canonical, ...aliases) {
|
|
520
|
+
for (const key of [canonical, ...aliases]) {
|
|
521
|
+
const value = params[key];
|
|
522
|
+
if (value !== undefined && value !== null)
|
|
523
|
+
return value;
|
|
524
|
+
}
|
|
525
|
+
return undefined;
|
|
526
|
+
}
|
|
527
|
+
/** The generation parameters every video capability forwards, de-aliased. */
|
|
528
|
+
function videoShapeParams(params) {
|
|
529
|
+
return {
|
|
530
|
+
num_frames: aliased(params, "num_frames", "numFrames", "frames"),
|
|
531
|
+
duration_seconds: aliased(params, "duration_seconds", "durationSeconds", "duration"),
|
|
532
|
+
aspect_ratio: aliased(params, "aspect_ratio", "aspectRatio", "aspect"),
|
|
533
|
+
resolution: aliased(params, "resolution")
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
/** The aspect ratios the video providers name, as width/height. */
|
|
537
|
+
const ASPECT_RATIOS = [
|
|
538
|
+
["21:9", 21 / 9],
|
|
539
|
+
["16:9", 16 / 9],
|
|
540
|
+
["4:3", 4 / 3],
|
|
541
|
+
["1:1", 1],
|
|
542
|
+
["3:4", 3 / 4],
|
|
543
|
+
["9:16", 9 / 16]
|
|
544
|
+
];
|
|
545
|
+
/** The listed ratio closest to `width/height`, or null for a bad size. */
|
|
546
|
+
export function nearestAspectRatio(width, height) {
|
|
547
|
+
if (!Number.isFinite(width) || !Number.isFinite(height))
|
|
548
|
+
return null;
|
|
549
|
+
if (width <= 0 || height <= 0)
|
|
550
|
+
return null;
|
|
551
|
+
const target = width / height;
|
|
552
|
+
let best = ASPECT_RATIOS[0];
|
|
553
|
+
for (const candidate of ASPECT_RATIOS) {
|
|
554
|
+
if (Math.abs(candidate[1] - target) < Math.abs(best[1] - target)) {
|
|
555
|
+
best = candidate;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return best[0];
|
|
559
|
+
}
|
|
560
|
+
const generateVideo = {
|
|
561
|
+
spec: generateVideoSpec,
|
|
562
|
+
impl: async (run, params) => {
|
|
563
|
+
const m = parseModelArgs(params);
|
|
564
|
+
if ("error" in m)
|
|
565
|
+
return m;
|
|
566
|
+
const prompt = params["prompt"];
|
|
567
|
+
if (!isNonEmptyString(prompt))
|
|
568
|
+
return { error: "prompt is required" };
|
|
569
|
+
return runMediaGeneration(run, params, {
|
|
570
|
+
capability: "text_to_video",
|
|
571
|
+
m,
|
|
572
|
+
type: "video",
|
|
573
|
+
namePrefix: "generated-video",
|
|
574
|
+
mime: "video/mp4",
|
|
575
|
+
params: {
|
|
576
|
+
prompt,
|
|
577
|
+
negative_prompt: aliased(params, "negative_prompt", "negativePrompt"),
|
|
578
|
+
...videoShapeParams(params)
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
const animateImage = {
|
|
584
|
+
spec: animateImageSpec,
|
|
585
|
+
impl: async (run, params) => {
|
|
586
|
+
const context = run.context;
|
|
587
|
+
const m = parseModelArgs(params);
|
|
588
|
+
if ("error" in m)
|
|
589
|
+
return m;
|
|
590
|
+
const inputFile = params["input_file"];
|
|
591
|
+
if (!isNonEmptyString(inputFile))
|
|
592
|
+
return { error: "input_file is required" };
|
|
593
|
+
let image;
|
|
594
|
+
try {
|
|
595
|
+
image = await readWorkspaceOrAssetFile(context, inputFile);
|
|
596
|
+
}
|
|
597
|
+
catch (e) {
|
|
598
|
+
return predictionError("image_to_video", m, e);
|
|
599
|
+
}
|
|
600
|
+
const shape = videoShapeParams(params);
|
|
601
|
+
// A vertical still animated at the provider's default aspect comes back
|
|
602
|
+
// 16:9, cropped or padded, and the caller finds out when the ad is cut:
|
|
603
|
+
// three 1280x720 beds under a 1080x1920 sequence. The source image is the
|
|
604
|
+
// best statement of intent available, so it sets the ratio when the call
|
|
605
|
+
// does not.
|
|
606
|
+
if (shape.aspect_ratio === undefined) {
|
|
607
|
+
const size = imagePixelSize(image);
|
|
608
|
+
const derived = size ? nearestAspectRatio(size.width, size.height) : null;
|
|
609
|
+
if (derived)
|
|
610
|
+
shape.aspect_ratio = derived;
|
|
611
|
+
}
|
|
612
|
+
return runMediaGeneration(run, params, {
|
|
613
|
+
capability: "image_to_video",
|
|
614
|
+
m,
|
|
615
|
+
type: "video",
|
|
616
|
+
namePrefix: "animated-video",
|
|
617
|
+
mime: "video/mp4",
|
|
618
|
+
params: { image, prompt: params["prompt"], ...shape }
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
/** Extensions that state a reference's kind without reading its bytes. */
|
|
623
|
+
const IMAGE_EXTENSIONS = new Set([
|
|
624
|
+
"png",
|
|
625
|
+
"jpg",
|
|
626
|
+
"jpeg",
|
|
627
|
+
"gif",
|
|
628
|
+
"bmp",
|
|
629
|
+
"webp",
|
|
630
|
+
"avif",
|
|
631
|
+
"heic",
|
|
632
|
+
"heif",
|
|
633
|
+
"tif",
|
|
634
|
+
"tiff"
|
|
635
|
+
]);
|
|
636
|
+
const VIDEO_EXTENSIONS = new Set([
|
|
637
|
+
"mp4",
|
|
638
|
+
"m4v",
|
|
639
|
+
"mov",
|
|
640
|
+
"webm",
|
|
641
|
+
"mkv",
|
|
642
|
+
"avi",
|
|
643
|
+
"mpeg",
|
|
644
|
+
"mpg",
|
|
645
|
+
"wmv"
|
|
646
|
+
]);
|
|
647
|
+
/**
|
|
648
|
+
* Whether a reference is an image or a video. The provider takes the two in
|
|
649
|
+
* separate lists — a video handed over as an image is rejected with an opaque
|
|
650
|
+
* provider error — so the kind has to be settled here.
|
|
651
|
+
*
|
|
652
|
+
* The extension decides when it says anything, because it is what the caller
|
|
653
|
+
* stated. Otherwise the bytes do: the image sniffer first (it owns the
|
|
654
|
+
* `ftyp`-based AVIF/HEIC cases), then the three video containers. A reference
|
|
655
|
+
* neither names nor looks like either is null, and the call refuses it rather
|
|
656
|
+
* than guessing.
|
|
657
|
+
*/
|
|
658
|
+
export function classifyReferenceMedia(file, bytes) {
|
|
659
|
+
const dot = file.lastIndexOf(".");
|
|
660
|
+
const ext = dot > -1 ? file.slice(dot + 1).toLowerCase() : "";
|
|
661
|
+
if (IMAGE_EXTENSIONS.has(ext))
|
|
662
|
+
return "image";
|
|
663
|
+
if (VIDEO_EXTENSIONS.has(ext))
|
|
664
|
+
return "video";
|
|
665
|
+
if (sniffImageFormat(bytes) !== "unknown")
|
|
666
|
+
return "image";
|
|
667
|
+
const at = (i) => bytes[i] ?? -1;
|
|
668
|
+
const tag = (offset, text) => [...text].every((ch, i) => at(offset + i) === ch.charCodeAt(0));
|
|
669
|
+
if (tag(4, "ftyp"))
|
|
670
|
+
return "video";
|
|
671
|
+
// Matroska / WebM EBML header.
|
|
672
|
+
if (at(0) === 0x1a && at(1) === 0x45 && at(2) === 0xdf && at(3) === 0xa3) {
|
|
673
|
+
return "video";
|
|
674
|
+
}
|
|
675
|
+
if (tag(0, "RIFF") && tag(8, "AVI "))
|
|
676
|
+
return "video";
|
|
677
|
+
return null;
|
|
678
|
+
}
|
|
679
|
+
const videoFromReferences = {
|
|
680
|
+
spec: videoFromReferencesSpec,
|
|
681
|
+
impl: async (run, params) => {
|
|
682
|
+
const context = run.context;
|
|
683
|
+
const m = parseModelArgs(params);
|
|
684
|
+
if ("error" in m)
|
|
685
|
+
return m;
|
|
686
|
+
const referenceFiles = params["reference_files"];
|
|
687
|
+
if (!Array.isArray(referenceFiles)) {
|
|
688
|
+
return { error: "reference_files must be an array of strings" };
|
|
689
|
+
}
|
|
690
|
+
const files = referenceFiles.filter(isNonEmptyString);
|
|
691
|
+
if (files.length === 0) {
|
|
692
|
+
return { error: "reference_files must name at least one reference" };
|
|
693
|
+
}
|
|
694
|
+
const images = [];
|
|
695
|
+
const videos = [];
|
|
696
|
+
for (const file of files) {
|
|
697
|
+
let bytes;
|
|
698
|
+
try {
|
|
699
|
+
bytes = await readWorkspaceOrAssetFile(context, file);
|
|
700
|
+
}
|
|
701
|
+
catch (e) {
|
|
702
|
+
return predictionError("reference_to_video", m, e);
|
|
703
|
+
}
|
|
704
|
+
const kind = classifyReferenceMedia(file, bytes);
|
|
705
|
+
if (kind === null) {
|
|
706
|
+
return {
|
|
707
|
+
error: `${file} is neither an image nor a video — reference_to_video takes only those`
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
(kind === "image" ? images : videos).push(bytes);
|
|
711
|
+
}
|
|
712
|
+
const useReferenceVideoAudio = aliased(params, "use_reference_video_audio", "useReferenceVideoAudio");
|
|
713
|
+
if (useReferenceVideoAudio === true && videos.length === 0) {
|
|
714
|
+
return {
|
|
715
|
+
error: "use_reference_video_audio needs a reference video to take the audio from"
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
const shape = videoShapeParams(params);
|
|
719
|
+
// Same reasoning as animate_image: a vertical reference rendered at the
|
|
720
|
+
// provider's default lands 16:9 and the crop is found at the cut. The
|
|
721
|
+
// first image reference states the intended shape when the call does not.
|
|
722
|
+
if (shape.aspect_ratio === undefined && images.length > 0) {
|
|
723
|
+
const size = imagePixelSize(images[0]);
|
|
724
|
+
const derived = size ? nearestAspectRatio(size.width, size.height) : null;
|
|
725
|
+
if (derived)
|
|
726
|
+
shape.aspect_ratio = derived;
|
|
727
|
+
}
|
|
728
|
+
return runMediaGeneration(run, params, {
|
|
729
|
+
capability: "reference_to_video",
|
|
730
|
+
m,
|
|
731
|
+
type: "video",
|
|
732
|
+
namePrefix: "reference-video",
|
|
733
|
+
mime: "video/mp4",
|
|
734
|
+
params: {
|
|
735
|
+
reference_images: images,
|
|
736
|
+
reference_videos: videos,
|
|
737
|
+
prompt: params["prompt"],
|
|
738
|
+
negative_prompt: aliased(params, "negative_prompt", "negativePrompt"),
|
|
739
|
+
use_reference_video_audio: useReferenceVideoAudio,
|
|
740
|
+
...shape
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
function int16ToUint8(samples) {
|
|
746
|
+
const bytes = new Uint8Array(samples.byteLength);
|
|
747
|
+
const view = new DataView(bytes.buffer);
|
|
748
|
+
for (let i = 0; i < samples.length; i++) {
|
|
749
|
+
view.setInt16(i * 2, samples[i], true);
|
|
750
|
+
}
|
|
751
|
+
return bytes;
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Wrap raw little-endian int16 PCM bytes in a minimal RIFF/WAVE container so
|
|
755
|
+
* the file is playable. Defaults match OpenAI's TTS PCM stream (24 kHz mono).
|
|
756
|
+
*/
|
|
757
|
+
function wrapPcmAsWav(pcm, sampleRate = 24000, channels = 1) {
|
|
758
|
+
const bitsPerSample = 16;
|
|
759
|
+
const byteRate = (sampleRate * channels * bitsPerSample) / 8;
|
|
760
|
+
const blockAlign = (channels * bitsPerSample) / 8;
|
|
761
|
+
const header = new Uint8Array(44);
|
|
762
|
+
const v = new DataView(header.buffer);
|
|
763
|
+
const w = (s, off) => {
|
|
764
|
+
for (let i = 0; i < s.length; i++)
|
|
765
|
+
v.setUint8(off + i, s.charCodeAt(i));
|
|
766
|
+
};
|
|
767
|
+
w("RIFF", 0);
|
|
768
|
+
v.setUint32(4, 36 + pcm.length, true);
|
|
769
|
+
w("WAVE", 8);
|
|
770
|
+
w("fmt ", 12);
|
|
771
|
+
v.setUint32(16, 16, true); // PCM chunk size
|
|
772
|
+
v.setUint16(20, 1, true); // PCM format
|
|
773
|
+
v.setUint16(22, channels, true);
|
|
774
|
+
v.setUint32(24, sampleRate, true);
|
|
775
|
+
v.setUint32(28, byteRate, true);
|
|
776
|
+
v.setUint16(32, blockAlign, true);
|
|
777
|
+
v.setUint16(34, bitsPerSample, true);
|
|
778
|
+
w("data", 36);
|
|
779
|
+
v.setUint32(40, pcm.length, true);
|
|
780
|
+
const out = new Uint8Array(header.length + pcm.length);
|
|
781
|
+
out.set(header, 0);
|
|
782
|
+
out.set(pcm, header.length);
|
|
783
|
+
return out;
|
|
784
|
+
}
|
|
785
|
+
const AUDIO_EXT_TO_FORMAT = {
|
|
786
|
+
mp3: "mp3",
|
|
787
|
+
wav: "wav",
|
|
788
|
+
flac: "flac",
|
|
789
|
+
opus: "opus",
|
|
790
|
+
ogg: "opus",
|
|
791
|
+
aac: "aac",
|
|
792
|
+
m4a: "aac"
|
|
793
|
+
};
|
|
794
|
+
function audioFormatFromOutputFile(outputFile) {
|
|
795
|
+
if (!outputFile)
|
|
796
|
+
return null;
|
|
797
|
+
const ext = path.extname(outputFile).slice(1).toLowerCase();
|
|
798
|
+
return AUDIO_EXT_TO_FORMAT[ext] ?? null;
|
|
799
|
+
}
|
|
800
|
+
function concatUint8(parts) {
|
|
801
|
+
let total = 0;
|
|
802
|
+
for (const p of parts)
|
|
803
|
+
total += p.length;
|
|
804
|
+
const out = new Uint8Array(total);
|
|
805
|
+
let offset = 0;
|
|
806
|
+
for (const p of parts) {
|
|
807
|
+
out.set(p, offset);
|
|
808
|
+
offset += p.length;
|
|
809
|
+
}
|
|
810
|
+
return out;
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* Ask for fully-encoded speech through whichever seam this context has.
|
|
814
|
+
*
|
|
815
|
+
* `context.textToSpeechEncoded` is the one `nodetool.audio.TextToSpeech` uses,
|
|
816
|
+
* and the one that emits the prediction events a run is billed and traced by,
|
|
817
|
+
* so it is tried first. Reaching past it to `getProvider` was the only path
|
|
818
|
+
* before, and it cost every FAL and KIE voice on a context that carries the
|
|
819
|
+
* prediction seams but not `getProvider`: the TypeError landed in the caller's
|
|
820
|
+
* catch, and the streaming fallback then reported "fal_ai does not support
|
|
821
|
+
* textToSpeech" — of a provider whose entire TTS catalog is encoded.
|
|
822
|
+
*/
|
|
823
|
+
async function encodedSpeech(context, m, params, generation) {
|
|
824
|
+
if (isFunction(context.textToSpeechEncoded)) {
|
|
825
|
+
return await context.textToSpeechEncoded({
|
|
826
|
+
...generation,
|
|
827
|
+
provider: m.provider,
|
|
828
|
+
capability: "text_to_speech",
|
|
829
|
+
model: m.model,
|
|
830
|
+
params: {
|
|
831
|
+
text: params.text,
|
|
832
|
+
voice: params.voice,
|
|
833
|
+
speed: params.speed,
|
|
834
|
+
audioFormat: params.audioFormat
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
if (isFunction(context.getProvider)) {
|
|
839
|
+
const provider = await context.getProvider(m.provider);
|
|
840
|
+
return await provider.textToSpeechEncoded({
|
|
841
|
+
text: params.text,
|
|
842
|
+
model: m.model,
|
|
843
|
+
voice: params.voice,
|
|
844
|
+
speed: params.speed,
|
|
845
|
+
audioFormat: params.audioFormat
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
throw new Error("this runtime's context has no encoded text_to_speech path");
|
|
849
|
+
}
|
|
850
|
+
const generateSpeech = {
|
|
851
|
+
spec: generateSpeechSpec,
|
|
852
|
+
impl: async (run, params) => {
|
|
853
|
+
const context = run.context;
|
|
854
|
+
const m = parseModelArgs(params);
|
|
855
|
+
if ("error" in m)
|
|
856
|
+
return m;
|
|
857
|
+
const text = params["text"];
|
|
858
|
+
if (!isNonEmptyString(text))
|
|
859
|
+
return { error: "text is required" };
|
|
860
|
+
const outputFile = isString(params["output_file"])
|
|
861
|
+
? params["output_file"]
|
|
862
|
+
: undefined;
|
|
863
|
+
const desiredFormat = audioFormatFromOutputFile(outputFile) ?? "mp3";
|
|
864
|
+
const generationId = randomUUID();
|
|
865
|
+
const generation = {
|
|
866
|
+
id: generationId,
|
|
867
|
+
origin: { surface: "capability", tool_call_id: toolCallIdOf(params) },
|
|
868
|
+
persist: outputFile ? { name: path.basename(outputFile) } : {}
|
|
869
|
+
};
|
|
870
|
+
const speechParams = {
|
|
871
|
+
text,
|
|
872
|
+
voice: params["voice"],
|
|
873
|
+
speed: params["speed"],
|
|
874
|
+
audioFormat: desiredFormat
|
|
875
|
+
};
|
|
876
|
+
if (params["background"] === true) {
|
|
877
|
+
const spec = {
|
|
878
|
+
capability: "text_to_speech",
|
|
879
|
+
m,
|
|
880
|
+
type: "audio",
|
|
881
|
+
namePrefix: "generated-speech",
|
|
882
|
+
params: speechParams
|
|
883
|
+
};
|
|
884
|
+
const started = startBackgroundGeneration(context, () => encodedSpeech(context, m, speechParams, generation));
|
|
885
|
+
if (!started) {
|
|
886
|
+
return backgroundGenerationLimitError();
|
|
887
|
+
}
|
|
888
|
+
return backgroundReceipt(generationId, spec);
|
|
889
|
+
}
|
|
890
|
+
try {
|
|
891
|
+
// Preferred path: ask the provider for fully-encoded audio in the
|
|
892
|
+
// desired container (mp3/wav/flac/...). Returns null when the provider
|
|
893
|
+
// doesn't support encoded TTS — we then fall through to streaming PCM.
|
|
894
|
+
let audio = null;
|
|
895
|
+
let mimeType;
|
|
896
|
+
let outputFileFinal = outputFile;
|
|
897
|
+
// The asset the seam saved on the encoded path, when it could.
|
|
898
|
+
let seamAssetId = null;
|
|
899
|
+
// Why the encoded path gave up, kept for the failure message. A provider
|
|
900
|
+
// that only does encoded TTS (FAL, KIE) leaves the streaming method as
|
|
901
|
+
// the base class's, which throws "<provider> does not support
|
|
902
|
+
// textToSpeech" — so discarding this error reported the one thing that
|
|
903
|
+
// was not wrong, and a session spent three rounds hunting for a TTS
|
|
904
|
+
// model when the real answer was in the sentence thrown here.
|
|
905
|
+
let encodedError;
|
|
906
|
+
try {
|
|
907
|
+
const encoded = await encodedSpeech(context, m, speechParams, generation);
|
|
908
|
+
if (encoded && encoded.data) {
|
|
909
|
+
audio = encoded.data;
|
|
910
|
+
mimeType = encoded.mimeType;
|
|
911
|
+
seamAssetId = await seamAssetFor(generationId);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
catch (e) {
|
|
915
|
+
encodedError = e instanceof Error ? e.message : String(e);
|
|
916
|
+
}
|
|
917
|
+
if (!audio) {
|
|
918
|
+
// Streaming path — provider returns either pre-encoded chunks
|
|
919
|
+
// (carrying mimeType) or raw int16 PCM samples that we must wrap in
|
|
920
|
+
// a WAV container before writing to disk so the file is playable.
|
|
921
|
+
const parts = [];
|
|
922
|
+
let pcmOnly = true;
|
|
923
|
+
// Capture the PCM sample rate from the stream — providers emit non-24k
|
|
924
|
+
// PCM (MiniMax 32000, Together varies). Hardcoding 24000 in the WAV
|
|
925
|
+
// header makes those play back at the wrong speed/pitch.
|
|
926
|
+
let pcmSampleRate;
|
|
927
|
+
try {
|
|
928
|
+
for await (const item of context.streamProviderPrediction({
|
|
929
|
+
id: generationId,
|
|
930
|
+
origin: generation.origin,
|
|
931
|
+
provider: m.provider,
|
|
932
|
+
capability: "text_to_speech",
|
|
933
|
+
model: m.model,
|
|
934
|
+
params: {
|
|
935
|
+
text,
|
|
936
|
+
voice: params["voice"],
|
|
937
|
+
speed: params["speed"]
|
|
938
|
+
}
|
|
939
|
+
})) {
|
|
940
|
+
const chunk = item;
|
|
941
|
+
if (chunk.data instanceof Uint8Array) {
|
|
942
|
+
parts.push(chunk.data);
|
|
943
|
+
if (chunk.mimeType)
|
|
944
|
+
mimeType = chunk.mimeType;
|
|
945
|
+
pcmOnly = false;
|
|
946
|
+
}
|
|
947
|
+
else if (isString(chunk.data)) {
|
|
948
|
+
parts.push(Buffer.from(chunk.data, "base64"));
|
|
949
|
+
if (chunk.mimeType)
|
|
950
|
+
mimeType = chunk.mimeType;
|
|
951
|
+
pcmOnly = false;
|
|
952
|
+
}
|
|
953
|
+
else if (chunk.samples) {
|
|
954
|
+
pcmSampleRate ??= chunk.sampleRate;
|
|
955
|
+
parts.push(int16ToUint8(chunk.samples));
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
catch (e) {
|
|
960
|
+
// Both paths failed. Report the encoded one first: on a provider
|
|
961
|
+
// that only does encoded TTS the streaming error is the base class's
|
|
962
|
+
// "does not support textToSpeech", which is true of the method and
|
|
963
|
+
// false of the provider.
|
|
964
|
+
if (encodedError) {
|
|
965
|
+
throw new Error(`${encodedError} (the streaming fallback then failed too: ${e instanceof Error ? e.message : String(e)})`);
|
|
966
|
+
}
|
|
967
|
+
throw e;
|
|
968
|
+
}
|
|
969
|
+
if (parts.length === 0) {
|
|
970
|
+
return {
|
|
971
|
+
error: encodedError
|
|
972
|
+
? `Provider returned no audio data: ${encodedError}`
|
|
973
|
+
: "Provider returned no audio data"
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
const merged = concatUint8(parts);
|
|
977
|
+
if (pcmOnly && !mimeType) {
|
|
978
|
+
// Wrap raw PCM in WAV so the bytes are playable. Rename .mp3 →
|
|
979
|
+
// .wav since the actual data is now WAV, not MP3. Honor the provider's
|
|
980
|
+
// actual sample rate (defaulting to 24k only when unknown).
|
|
981
|
+
audio = wrapPcmAsWav(merged, pcmSampleRate ?? 24000);
|
|
982
|
+
mimeType = "audio/wav";
|
|
983
|
+
if (outputFileFinal) {
|
|
984
|
+
const dir = path.dirname(outputFileFinal);
|
|
985
|
+
const base = path.basename(outputFileFinal, path.extname(outputFileFinal));
|
|
986
|
+
outputFileFinal = path.join(dir === "." ? "" : dir, `${base}.wav`);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
else {
|
|
990
|
+
audio = merged;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
const mime = mimeType ?? "audio/mpeg";
|
|
994
|
+
const persisted = await finishOutput(context, audio, seamAssetId
|
|
995
|
+
? [
|
|
996
|
+
{
|
|
997
|
+
asset_id: seamAssetId,
|
|
998
|
+
uri: `asset://${seamAssetId}.${MIME_TO_EXT[mime] ?? "bin"}`
|
|
999
|
+
}
|
|
1000
|
+
]
|
|
1001
|
+
: [], {
|
|
1002
|
+
namePrefix: "generated-speech",
|
|
1003
|
+
mime,
|
|
1004
|
+
outputFile: outputFileFinal
|
|
1005
|
+
});
|
|
1006
|
+
return {
|
|
1007
|
+
type: "audio",
|
|
1008
|
+
provider: m.provider,
|
|
1009
|
+
model: m.model,
|
|
1010
|
+
generation_id: generationId,
|
|
1011
|
+
...persisted
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
catch (e) {
|
|
1015
|
+
return {
|
|
1016
|
+
...predictionError("text_to_speech", m, e),
|
|
1017
|
+
generation_id: generationId
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1022
|
+
/**
|
|
1023
|
+
* Music from a prompt — the counterpart to {@link generateSpeech}, and the
|
|
1024
|
+
* hole every other generation capability made conspicuous.
|
|
1025
|
+
*
|
|
1026
|
+
* Without it, scoring a cut meant running `nodetool.audio.TextToMusic` through
|
|
1027
|
+
* `run_node`: a one-node graph, and therefore the graph validator, a typed
|
|
1028
|
+
* `music_model` property and a model ref to satisfy before a single second of
|
|
1029
|
+
* audio existed. A live session spent five rounds there and shipped silent.
|
|
1030
|
+
*/
|
|
1031
|
+
const generateMusic = {
|
|
1032
|
+
spec: generateMusicSpec,
|
|
1033
|
+
impl: async (run, params) => {
|
|
1034
|
+
const context = run.context;
|
|
1035
|
+
const m = parseModelArgs(params);
|
|
1036
|
+
if ("error" in m)
|
|
1037
|
+
return m;
|
|
1038
|
+
const prompt = params["prompt"];
|
|
1039
|
+
if (!isNonEmptyString(prompt))
|
|
1040
|
+
return { error: "prompt is required" };
|
|
1041
|
+
if (!isFunction(context.textToMusic)) {
|
|
1042
|
+
return {
|
|
1043
|
+
error: "this runtime's context has no text_to_music path"
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
const outputFile = isString(params["output_file"])
|
|
1047
|
+
? params["output_file"]
|
|
1048
|
+
: undefined;
|
|
1049
|
+
const desiredFormat = audioFormatFromOutputFile(outputFile) ?? "mp3";
|
|
1050
|
+
const generationId = randomUUID();
|
|
1051
|
+
const musicParams = {
|
|
1052
|
+
prompt,
|
|
1053
|
+
lyrics: params["lyrics"],
|
|
1054
|
+
duration_seconds: aliased(params, "duration_seconds", "durationSeconds", "duration"),
|
|
1055
|
+
audioFormat: desiredFormat
|
|
1056
|
+
};
|
|
1057
|
+
const req = {
|
|
1058
|
+
id: generationId,
|
|
1059
|
+
provider: m.provider,
|
|
1060
|
+
capability: "text_to_music",
|
|
1061
|
+
model: m.model,
|
|
1062
|
+
params: musicParams,
|
|
1063
|
+
origin: { surface: "capability", tool_call_id: toolCallIdOf(params) },
|
|
1064
|
+
persist: outputFile ? { name: path.basename(outputFile) } : {}
|
|
1065
|
+
};
|
|
1066
|
+
const spec = {
|
|
1067
|
+
capability: "text_to_music",
|
|
1068
|
+
m,
|
|
1069
|
+
type: "audio",
|
|
1070
|
+
namePrefix: "generated-music",
|
|
1071
|
+
params: musicParams
|
|
1072
|
+
};
|
|
1073
|
+
if (params["background"] === true) {
|
|
1074
|
+
const started = startBackgroundGeneration(context, () => context.textToMusic(req));
|
|
1075
|
+
if (!started) {
|
|
1076
|
+
return backgroundGenerationLimitError();
|
|
1077
|
+
}
|
|
1078
|
+
return backgroundReceipt(generationId, spec);
|
|
1079
|
+
}
|
|
1080
|
+
try {
|
|
1081
|
+
const encoded = await context.textToMusic(req);
|
|
1082
|
+
if (!encoded?.data || encoded.data.length === 0) {
|
|
1083
|
+
return {
|
|
1084
|
+
error: "Provider returned no audio data",
|
|
1085
|
+
generation_id: generationId
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
const mime = encoded.mimeType ?? "audio/mpeg";
|
|
1089
|
+
const seamAssetId = await seamAssetFor(generationId);
|
|
1090
|
+
const persisted = await finishOutput(context, encoded.data, seamAssetId
|
|
1091
|
+
? [
|
|
1092
|
+
{
|
|
1093
|
+
asset_id: seamAssetId,
|
|
1094
|
+
uri: `asset://${seamAssetId}.${MIME_TO_EXT[mime] ?? "bin"}`
|
|
1095
|
+
}
|
|
1096
|
+
]
|
|
1097
|
+
: [], { namePrefix: "generated-music", mime, outputFile });
|
|
1098
|
+
return {
|
|
1099
|
+
type: "audio",
|
|
1100
|
+
provider: m.provider,
|
|
1101
|
+
model: m.model,
|
|
1102
|
+
generation_id: generationId,
|
|
1103
|
+
...persisted
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
catch (e) {
|
|
1107
|
+
return {
|
|
1108
|
+
...predictionError("text_to_music", m, e),
|
|
1109
|
+
generation_id: generationId
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
};
|
|
1114
|
+
const transcribeAudio = {
|
|
1115
|
+
spec: transcribeAudioSpec,
|
|
1116
|
+
impl: async (run, params) => {
|
|
1117
|
+
const context = run.context;
|
|
1118
|
+
const m = parseModelArgs(params);
|
|
1119
|
+
if ("error" in m)
|
|
1120
|
+
return m;
|
|
1121
|
+
const inputFile = params["input_file"];
|
|
1122
|
+
if (!isNonEmptyString(inputFile))
|
|
1123
|
+
return { error: "input_file is required" };
|
|
1124
|
+
try {
|
|
1125
|
+
const audio = await readWorkspaceOrAssetFile(context, inputFile);
|
|
1126
|
+
const result = (await context.runProviderPrediction({
|
|
1127
|
+
provider: m.provider,
|
|
1128
|
+
capability: "automatic_speech_recognition",
|
|
1129
|
+
model: m.model,
|
|
1130
|
+
params: {
|
|
1131
|
+
audio,
|
|
1132
|
+
language: params["language"],
|
|
1133
|
+
prompt: params["prompt"]
|
|
1134
|
+
}
|
|
1135
|
+
}));
|
|
1136
|
+
const text = String(result.text ?? "");
|
|
1137
|
+
return {
|
|
1138
|
+
type: "transcription",
|
|
1139
|
+
provider: m.provider,
|
|
1140
|
+
model: m.model,
|
|
1141
|
+
text: text.length > MAX_INLINE_TEXT_PREVIEW
|
|
1142
|
+
? text.slice(0, MAX_INLINE_TEXT_PREVIEW) +
|
|
1143
|
+
`… [${text.length - MAX_INLINE_TEXT_PREVIEW} chars truncated]`
|
|
1144
|
+
: text,
|
|
1145
|
+
full_length: text.length,
|
|
1146
|
+
chunks: Array.isArray(result.chunks) ? result.chunks.length : 0
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
catch (e) {
|
|
1150
|
+
return {
|
|
1151
|
+
error: `transcribe failed: ${e instanceof Error ? e.message : String(e)}`
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
const embedText = {
|
|
1157
|
+
spec: embedTextSpec,
|
|
1158
|
+
impl: async (run, params) => {
|
|
1159
|
+
const context = run.context;
|
|
1160
|
+
const m = parseModelArgs(params);
|
|
1161
|
+
if ("error" in m)
|
|
1162
|
+
return m;
|
|
1163
|
+
const text = params["text"];
|
|
1164
|
+
if (!isString(text) && !Array.isArray(text))
|
|
1165
|
+
return { error: "text must be a string or array of strings" };
|
|
1166
|
+
try {
|
|
1167
|
+
const result = (await context.runProviderPrediction({
|
|
1168
|
+
provider: m.provider,
|
|
1169
|
+
capability: "generate_embedding",
|
|
1170
|
+
model: m.model,
|
|
1171
|
+
params: {
|
|
1172
|
+
text,
|
|
1173
|
+
dimensions: params["dimensions"]
|
|
1174
|
+
}
|
|
1175
|
+
}));
|
|
1176
|
+
return {
|
|
1177
|
+
type: "embedding",
|
|
1178
|
+
provider: m.provider,
|
|
1179
|
+
model: m.model,
|
|
1180
|
+
count: result.length,
|
|
1181
|
+
dimensions: result[0]?.length ?? 0,
|
|
1182
|
+
embeddings: result
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
catch (e) {
|
|
1186
|
+
return {
|
|
1187
|
+
error: `generate_embedding failed: ${e instanceof Error ? e.message : String(e)}`
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
};
|
|
1192
|
+
function parseJudgeModelArgs(params) {
|
|
1193
|
+
const provider = params["provider"];
|
|
1194
|
+
const model = params["model"];
|
|
1195
|
+
if (!isNonEmptyString(provider)) {
|
|
1196
|
+
return {
|
|
1197
|
+
error: "provider must be a non-empty string (use find_model with a vision-capable chat model)"
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
if (!isNonEmptyString(model)) {
|
|
1201
|
+
return {
|
|
1202
|
+
error: "model must be a non-empty string (use find_model with a vision-capable chat model)"
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
return { provider, model };
|
|
1206
|
+
}
|
|
1207
|
+
/** Normalize a media source so the context media resolver can inline it. */
|
|
1208
|
+
function normalizeMediaSource(source) {
|
|
1209
|
+
const trimmed = source.trim();
|
|
1210
|
+
if (trimmed.startsWith("data:") ||
|
|
1211
|
+
trimmed.startsWith("asset://") ||
|
|
1212
|
+
/^https?:\/\//i.test(trimmed)) {
|
|
1213
|
+
return trimmed;
|
|
1214
|
+
}
|
|
1215
|
+
// Bare asset ids (what list_images and generate_image return) become
|
|
1216
|
+
// asset:// URIs, which resolveMessageMediaUris inlines as data URIs.
|
|
1217
|
+
return `asset://${trimmed}`;
|
|
1218
|
+
}
|
|
1219
|
+
function imagePart(source) {
|
|
1220
|
+
return {
|
|
1221
|
+
type: "image_url",
|
|
1222
|
+
image: { type: "image", uri: normalizeMediaSource(source) }
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
function videoPart(source) {
|
|
1226
|
+
return {
|
|
1227
|
+
type: "video",
|
|
1228
|
+
video: { type: "video", uri: normalizeMediaSource(source) }
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
function textPart(text) {
|
|
1232
|
+
return { type: "text", text };
|
|
1233
|
+
}
|
|
1234
|
+
/** Pull the text out of a provider response message. */
|
|
1235
|
+
function messageText(message) {
|
|
1236
|
+
const content = message.content;
|
|
1237
|
+
if (isString(content))
|
|
1238
|
+
return content;
|
|
1239
|
+
if (Array.isArray(content)) {
|
|
1240
|
+
return content
|
|
1241
|
+
.map((part) => (part.type === "text" ? part.text : ""))
|
|
1242
|
+
.filter(Boolean)
|
|
1243
|
+
.join("\n");
|
|
1244
|
+
}
|
|
1245
|
+
return "";
|
|
1246
|
+
}
|
|
1247
|
+
async function judgeCall(context, m, content, maxTokens = JUDGE_MAX_TOKENS) {
|
|
1248
|
+
const result = (await context.runProviderPrediction({
|
|
1249
|
+
provider: m.provider,
|
|
1250
|
+
capability: "generate_message",
|
|
1251
|
+
model: m.model,
|
|
1252
|
+
params: {
|
|
1253
|
+
messages: [{ role: "user", content }],
|
|
1254
|
+
max_tokens: maxTokens,
|
|
1255
|
+
temperature: 0
|
|
1256
|
+
}
|
|
1257
|
+
}));
|
|
1258
|
+
return messageText(result);
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Whether a model reply reads as cut off rather than merely wrong.
|
|
1262
|
+
*
|
|
1263
|
+
* A judge on a reasoning model spends its ceiling thinking and returns half a
|
|
1264
|
+
* sentence; the caller then sees "did not return parseable JSON" and re-runs
|
|
1265
|
+
* the same call at the same budget. Naming the cause in the error is the
|
|
1266
|
+
* difference between one retry and three.
|
|
1267
|
+
*/
|
|
1268
|
+
export function looksTruncated(text) {
|
|
1269
|
+
const trimmed = text.trimEnd();
|
|
1270
|
+
if (trimmed.length === 0)
|
|
1271
|
+
return false;
|
|
1272
|
+
if (/[.!?\]}"]$/.test(trimmed))
|
|
1273
|
+
return false;
|
|
1274
|
+
return true;
|
|
1275
|
+
}
|
|
1276
|
+
function tasteBlock(params) {
|
|
1277
|
+
const profile = params["taste_profile"];
|
|
1278
|
+
if (!isNonBlankString(profile))
|
|
1279
|
+
return "";
|
|
1280
|
+
return `\n\nThe user's known aesthetic preferences (weigh these alongside the brief):\n${profile.trim()}`;
|
|
1281
|
+
}
|
|
1282
|
+
/**
|
|
1283
|
+
* A critique out of a judge reply, whole or cut short.
|
|
1284
|
+
*
|
|
1285
|
+
* The reply is a report, not an instruction: a `verdict` plus two lists whose
|
|
1286
|
+
* entries stand alone. A judge that hits its token ceiling mid-list has still
|
|
1287
|
+
* said everything before the cut, so a truncated reply is salvaged rather than
|
|
1288
|
+
* thrown away — before this, a run lost a usable verdict and every defect the
|
|
1289
|
+
* judge had already named.
|
|
1290
|
+
*/
|
|
1291
|
+
function parseCritique(text) {
|
|
1292
|
+
const parsed = extractJSONAllowingTruncation(text);
|
|
1293
|
+
if (!isRecord(parsed)) {
|
|
1294
|
+
return null;
|
|
1295
|
+
}
|
|
1296
|
+
const obj = parsed;
|
|
1297
|
+
const verdict = obj["verdict"] === "pass" ? "pass" : "revise";
|
|
1298
|
+
const defects = Array.isArray(obj["defects"])
|
|
1299
|
+
? obj["defects"]
|
|
1300
|
+
.filter(isObjectLike)
|
|
1301
|
+
.map((d) => ({
|
|
1302
|
+
defect: String(d["defect"] ?? ""),
|
|
1303
|
+
location: String(d["location"] ?? ""),
|
|
1304
|
+
fix: String(d["fix"] ?? "")
|
|
1305
|
+
}))
|
|
1306
|
+
.filter((d) => d.defect)
|
|
1307
|
+
: [];
|
|
1308
|
+
const strengths = Array.isArray(obj["strengths"])
|
|
1309
|
+
? obj["strengths"].map(String).filter(Boolean)
|
|
1310
|
+
: [];
|
|
1311
|
+
return { verdict, defects, strengths };
|
|
1312
|
+
}
|
|
1313
|
+
const critiqueImage = {
|
|
1314
|
+
spec: critiqueImageSpec,
|
|
1315
|
+
impl: async (run, params) => {
|
|
1316
|
+
const context = run.context;
|
|
1317
|
+
const m = parseJudgeModelArgs(params);
|
|
1318
|
+
if ("error" in m)
|
|
1319
|
+
return m;
|
|
1320
|
+
const image = params["image"];
|
|
1321
|
+
const brief = params["brief"];
|
|
1322
|
+
if (!isNonEmptyString(image))
|
|
1323
|
+
return { error: "image is required" };
|
|
1324
|
+
if (!isNonEmptyString(brief))
|
|
1325
|
+
return { error: "brief is required" };
|
|
1326
|
+
const prompt = `You are a demanding art director reviewing one image against a brief.` +
|
|
1327
|
+
`\n\nBrief:\n${brief}${tasteBlock(params)}` +
|
|
1328
|
+
`\n\nExamine the image and report only defects you can point at: things that are` +
|
|
1329
|
+
` wrong, missing relative to the brief, or technically broken (anatomy, geometry,` +
|
|
1330
|
+
` illegible text, composition, lighting inconsistencies). For each defect say` +
|
|
1331
|
+
` exactly where it is and the concrete change that fixes it.` +
|
|
1332
|
+
`\n\nRules:` +
|
|
1333
|
+
`\n- Never suggest adding embellishment or "more detail" — only fixes to named problems.` +
|
|
1334
|
+
`\n- If the composition itself is wrong for the brief, say so explicitly; that means` +
|
|
1335
|
+
` regenerating, not patching.` +
|
|
1336
|
+
`\n- Verdict "pass" only if the image fulfills the brief with no defect a client would notice.` +
|
|
1337
|
+
`\n\nRespond with JSON only:` +
|
|
1338
|
+
`\n{"verdict": "pass" | "revise", "defects": [{"defect": "...", "location": "...",` +
|
|
1339
|
+
` "fix": "..."}], "strengths": ["..."]}`;
|
|
1340
|
+
try {
|
|
1341
|
+
const text = await judgeCall(context, m, [
|
|
1342
|
+
textPart(prompt),
|
|
1343
|
+
imagePart(image)
|
|
1344
|
+
]);
|
|
1345
|
+
const critique = parseCritique(text);
|
|
1346
|
+
if (!critique) {
|
|
1347
|
+
return {
|
|
1348
|
+
error: `Judge did not return parseable JSON` +
|
|
1349
|
+
`${looksTruncated(text) ? " (the reply stops mid-sentence — it hit the token ceiling; raise max_tokens or pick a model that does not spend the budget on reasoning)" : ""}` +
|
|
1350
|
+
`: ${text.slice(0, 300)}`
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
return {
|
|
1354
|
+
type: "critique",
|
|
1355
|
+
provider: m.provider,
|
|
1356
|
+
model: m.model,
|
|
1357
|
+
...critique
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
catch (e) {
|
|
1361
|
+
return {
|
|
1362
|
+
error: `critique_image failed: ${e instanceof Error ? e.message : String(e)}`
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
};
|
|
1367
|
+
function parsePairVerdict(text) {
|
|
1368
|
+
const parsed = extractJSONAllowingTruncation(text);
|
|
1369
|
+
if (!isRecord(parsed))
|
|
1370
|
+
return null;
|
|
1371
|
+
const obj = parsed;
|
|
1372
|
+
const winner = Number(obj["winner"]);
|
|
1373
|
+
if (winner !== 1 && winner !== 2)
|
|
1374
|
+
return null;
|
|
1375
|
+
return { winner, reason: String(obj["reason"] ?? "") };
|
|
1376
|
+
}
|
|
1377
|
+
const compareImages = {
|
|
1378
|
+
spec: compareImagesSpec,
|
|
1379
|
+
impl: async (run, params) => {
|
|
1380
|
+
const context = run.context;
|
|
1381
|
+
const m = parseJudgeModelArgs(params);
|
|
1382
|
+
if ("error" in m)
|
|
1383
|
+
return m;
|
|
1384
|
+
const images = params["images"];
|
|
1385
|
+
const brief = params["brief"];
|
|
1386
|
+
if (!Array.isArray(images) ||
|
|
1387
|
+
images.length < 2 ||
|
|
1388
|
+
images.some((i) => !isNonEmptyString(i))) {
|
|
1389
|
+
return { error: "images must be an array of 2-8 non-empty strings" };
|
|
1390
|
+
}
|
|
1391
|
+
if (images.length > MAX_COMPARE_IMAGES) {
|
|
1392
|
+
return {
|
|
1393
|
+
error: `images must contain at most ${MAX_COMPARE_IMAGES} candidates`
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
if (!isNonEmptyString(brief))
|
|
1397
|
+
return { error: "brief is required" };
|
|
1398
|
+
const prompt = `You are judging which of two images better fulfills a creative brief.` +
|
|
1399
|
+
`\n\nBrief:\n${brief}${tasteBlock(params)}` +
|
|
1400
|
+
`\n\nImage 1 is shown first, image 2 second. Judge fulfillment of the brief and` +
|
|
1401
|
+
` craft (composition, coherence, technical execution) — not which image is busier` +
|
|
1402
|
+
` or more embellished. You must pick exactly one winner.` +
|
|
1403
|
+
`\n\nRespond with JSON only: {"winner": 1 | 2, "reason": "one sentence"}`;
|
|
1404
|
+
const judgePair = async (a, b) => {
|
|
1405
|
+
const call = async (first, second) => {
|
|
1406
|
+
const text = await judgeCall(context, m, [
|
|
1407
|
+
textPart(prompt),
|
|
1408
|
+
imagePart(first),
|
|
1409
|
+
imagePart(second)
|
|
1410
|
+
]);
|
|
1411
|
+
const verdict = parsePairVerdict(text);
|
|
1412
|
+
if (!verdict) {
|
|
1413
|
+
throw new Error(`Judge did not return parseable JSON: ${text.slice(0, 200)}`);
|
|
1414
|
+
}
|
|
1415
|
+
return {
|
|
1416
|
+
winner: verdict.winner === 1 ? first : second,
|
|
1417
|
+
reason: verdict.reason
|
|
1418
|
+
};
|
|
1419
|
+
};
|
|
1420
|
+
try {
|
|
1421
|
+
// Same pair, both presentation orders: an order-dependent preference
|
|
1422
|
+
// cancels out; only a stable preference wins outright.
|
|
1423
|
+
const [forward, reversed] = [await call(a, b), await call(b, a)];
|
|
1424
|
+
if (forward.winner === reversed.winner) {
|
|
1425
|
+
return { winner: forward.winner, reason: forward.reason };
|
|
1426
|
+
}
|
|
1427
|
+
// crypto randomInt over Math.random: not security-sensitive (it only
|
|
1428
|
+
// picks the tiebreak presentation order), but it keeps CodeQL's
|
|
1429
|
+
// insecure-randomness rule quiet without an exception.
|
|
1430
|
+
const tiebreak = randomInt(2) === 0 ? await call(a, b) : await call(b, a);
|
|
1431
|
+
return {
|
|
1432
|
+
winner: tiebreak.winner,
|
|
1433
|
+
reason: `(order-sensitive verdict, tiebreak) ${tiebreak.reason}`
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
catch (e) {
|
|
1437
|
+
return { error: e instanceof Error ? e.message : String(e) };
|
|
1438
|
+
}
|
|
1439
|
+
};
|
|
1440
|
+
const matches = [];
|
|
1441
|
+
let round = images.map(String);
|
|
1442
|
+
try {
|
|
1443
|
+
while (round.length > 1) {
|
|
1444
|
+
const next = [];
|
|
1445
|
+
for (let i = 0; i + 1 < round.length; i += 2) {
|
|
1446
|
+
const result = await judgePair(round[i], round[i + 1]);
|
|
1447
|
+
if ("error" in result)
|
|
1448
|
+
return { error: `compare_images failed: ${result.error}` };
|
|
1449
|
+
matches.push({
|
|
1450
|
+
a: round[i],
|
|
1451
|
+
b: round[i + 1],
|
|
1452
|
+
winner: result.winner,
|
|
1453
|
+
agreed: !result.reason.startsWith("(order-sensitive"),
|
|
1454
|
+
reason: result.reason
|
|
1455
|
+
});
|
|
1456
|
+
next.push(result.winner);
|
|
1457
|
+
}
|
|
1458
|
+
if (round.length % 2 === 1)
|
|
1459
|
+
next.push(round[round.length - 1]);
|
|
1460
|
+
round = next;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
catch (e) {
|
|
1464
|
+
return {
|
|
1465
|
+
error: `compare_images failed: ${e instanceof Error ? e.message : String(e)}`
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
return {
|
|
1469
|
+
type: "comparison",
|
|
1470
|
+
provider: m.provider,
|
|
1471
|
+
model: m.model,
|
|
1472
|
+
winner: round[0],
|
|
1473
|
+
matches,
|
|
1474
|
+
note: "Winner of a pairwise knockout. Other candidates were not deleted — " +
|
|
1475
|
+
"surface them to the user if the pick looks wrong."
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
};
|
|
1479
|
+
const scoreImageAdherence = {
|
|
1480
|
+
spec: scoreImageAdherenceSpec,
|
|
1481
|
+
impl: async (run, params) => {
|
|
1482
|
+
const context = run.context;
|
|
1483
|
+
const m = parseJudgeModelArgs(params);
|
|
1484
|
+
if ("error" in m)
|
|
1485
|
+
return m;
|
|
1486
|
+
const image = params["image"];
|
|
1487
|
+
const brief = params["brief"];
|
|
1488
|
+
if (!isNonEmptyString(image))
|
|
1489
|
+
return { error: "image is required" };
|
|
1490
|
+
if (!isNonEmptyString(brief))
|
|
1491
|
+
return { error: "brief is required" };
|
|
1492
|
+
try {
|
|
1493
|
+
let questions = Array.isArray(params["questions"])
|
|
1494
|
+
? params["questions"].map(String).filter(Boolean)
|
|
1495
|
+
: [];
|
|
1496
|
+
if (questions.length === 0) {
|
|
1497
|
+
const decomposeText = await judgeCall(context, m, [
|
|
1498
|
+
textPart(`Decompose this creative brief into at most ${MAX_ADHERENCE_QUESTIONS} atomic` +
|
|
1499
|
+
` yes/no questions, each verifiable by looking at a single image. Cover every` +
|
|
1500
|
+
` explicit requirement (subjects, counts, colors, text, style, composition,` +
|
|
1501
|
+
` mood). Phrase each so "yes" means the requirement is met. Skip anything not` +
|
|
1502
|
+
` visually checkable.` +
|
|
1503
|
+
`\n\nBrief:\n${brief}` +
|
|
1504
|
+
`\n\nRespond with JSON only: {"questions": ["..."]}`)
|
|
1505
|
+
]);
|
|
1506
|
+
const parsed = extractJSON(decomposeText);
|
|
1507
|
+
const list = isRecord(parsed) ? parsed["questions"] : parsed;
|
|
1508
|
+
questions = Array.isArray(list) ? list.map(String).filter(Boolean) : [];
|
|
1509
|
+
if (questions.length === 0) {
|
|
1510
|
+
return {
|
|
1511
|
+
error: `Could not decompose the brief into checks: ${decomposeText.slice(0, 300)}`
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
questions = questions.slice(0, MAX_ADHERENCE_QUESTIONS);
|
|
1516
|
+
const answerText = await judgeCall(context, m, [
|
|
1517
|
+
textPart(`Answer each question about the image with a strict yes or no. "yes" only if` +
|
|
1518
|
+
` the image clearly satisfies it; when unsure, answer "no" and say why in the note.` +
|
|
1519
|
+
`\n\nQuestions:\n${questions.map((q, i) => `${i + 1}. ${q}`).join("\n")}` +
|
|
1520
|
+
`\n\nRespond with JSON only:` +
|
|
1521
|
+
`\n{"answers": [{"question": "...", "answer": "yes" | "no", "note": "..."}]}`),
|
|
1522
|
+
imagePart(image)
|
|
1523
|
+
]);
|
|
1524
|
+
const parsed = extractJSON(answerText);
|
|
1525
|
+
const rawAnswers = isRecord(parsed) ? parsed["answers"] : null;
|
|
1526
|
+
if (!Array.isArray(rawAnswers) || rawAnswers.length === 0) {
|
|
1527
|
+
return {
|
|
1528
|
+
error: `Judge did not return parseable answers: ${answerText.slice(0, 300)}`
|
|
1529
|
+
};
|
|
1530
|
+
}
|
|
1531
|
+
const answers = rawAnswers
|
|
1532
|
+
.filter(isObjectLike)
|
|
1533
|
+
.map((a) => ({
|
|
1534
|
+
question: String(a["question"] ?? ""),
|
|
1535
|
+
answer: a["answer"] === "yes" ? "yes" : "no",
|
|
1536
|
+
note: String(a["note"] ?? "")
|
|
1537
|
+
}));
|
|
1538
|
+
const passed = answers.filter((a) => a.answer === "yes").length;
|
|
1539
|
+
return {
|
|
1540
|
+
type: "adherence",
|
|
1541
|
+
provider: m.provider,
|
|
1542
|
+
model: m.model,
|
|
1543
|
+
score: answers.length ? passed / answers.length : 0,
|
|
1544
|
+
passed,
|
|
1545
|
+
total: answers.length,
|
|
1546
|
+
failed: answers.filter((a) => a.answer === "no"),
|
|
1547
|
+
answers
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1550
|
+
catch (e) {
|
|
1551
|
+
return {
|
|
1552
|
+
error: `score_image_adherence failed: ${e instanceof Error ? e.message : String(e)}`
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
};
|
|
1557
|
+
// ---------------------------------------------------------------------------
|
|
1558
|
+
// understand_video
|
|
1559
|
+
// ---------------------------------------------------------------------------
|
|
1560
|
+
/**
|
|
1561
|
+
* Read a video with a multimodal chat model.
|
|
1562
|
+
*
|
|
1563
|
+
* The video rides as a `video` content part next to the instruction; the
|
|
1564
|
+
* context's media resolver inlines an `asset://` URI and the provider decides
|
|
1565
|
+
* whether the bytes go inline or through its files API.
|
|
1566
|
+
*
|
|
1567
|
+
* A provider with no video content part is not refused here any more: the
|
|
1568
|
+
* runtime samples the clip into stills with ffmpeg and sends those. The reply
|
|
1569
|
+
* carries `read_as` so the caller knows which of the two it got — a frame read
|
|
1570
|
+
* has no audio and nothing between the samples, and an answer that depends on
|
|
1571
|
+
* either should be treated as a guess.
|
|
1572
|
+
*/
|
|
1573
|
+
const understandVideo = {
|
|
1574
|
+
spec: understandVideoSpec,
|
|
1575
|
+
impl: async (run, params) => {
|
|
1576
|
+
const m = parseJudgeModelArgs(params);
|
|
1577
|
+
if ("error" in m)
|
|
1578
|
+
return m;
|
|
1579
|
+
const video = params["video"];
|
|
1580
|
+
if (!isNonEmptyString(video)) {
|
|
1581
|
+
return { error: "video is required" };
|
|
1582
|
+
}
|
|
1583
|
+
const promptParam = params["prompt"];
|
|
1584
|
+
const prompt = isNonBlankString(promptParam)
|
|
1585
|
+
? promptParam
|
|
1586
|
+
: DEFAULT_VIDEO_PROMPT;
|
|
1587
|
+
const requested = Number(params["max_tokens"]);
|
|
1588
|
+
const maxTokens = Number.isFinite(requested) && requested > 0
|
|
1589
|
+
? Math.min(Math.floor(requested), MAX_UNDERSTAND_VIDEO_TOKENS)
|
|
1590
|
+
: DEFAULT_UNDERSTAND_VIDEO_TOKENS;
|
|
1591
|
+
try {
|
|
1592
|
+
const native = await run.context.providerSupportsVideoInput(m.provider);
|
|
1593
|
+
const text = await judgeCall(run.context, m, [textPart(prompt), videoPart(video)], maxTokens);
|
|
1594
|
+
return {
|
|
1595
|
+
text,
|
|
1596
|
+
provider: m.provider,
|
|
1597
|
+
model: m.model,
|
|
1598
|
+
read_as: native ? "video" : "sampled_frames",
|
|
1599
|
+
// A reasoning model spends `max_tokens` on thinking and returns a
|
|
1600
|
+
// fragment. Without this the caller reads half an answer as the whole
|
|
1601
|
+
// answer — one run acted on "the clip shows a man attempting to" and
|
|
1602
|
+
// never learned the sentence had been cut.
|
|
1603
|
+
truncated: looksTruncated(text),
|
|
1604
|
+
max_tokens: maxTokens
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1607
|
+
catch (e) {
|
|
1608
|
+
return {
|
|
1609
|
+
error: `understand_video failed: ${e instanceof Error ? e.message : String(e)}`
|
|
1610
|
+
};
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
};
|
|
1614
|
+
/**
|
|
1615
|
+
* The gated read behind a media reference.
|
|
1616
|
+
*
|
|
1617
|
+
* The sandbox's own `media.bytes` needs a `ProcessingContext`, which a chat
|
|
1618
|
+
* action deliberately runs without (#4780) — so a chat user could generate an
|
|
1619
|
+
* image and never read it back. This is the same resolution past the
|
|
1620
|
+
* permission gate, with the context the run already carries.
|
|
1621
|
+
*
|
|
1622
|
+
* A filesystem path is refused rather than contained here: `read_file` is the
|
|
1623
|
+
* gated way to a workspace file, and a second containment rule beside
|
|
1624
|
+
* `resolveGuestPath` is the thing worth not having.
|
|
1625
|
+
*/
|
|
1626
|
+
const readMediaBytes = {
|
|
1627
|
+
spec: readMediaBytesSpec,
|
|
1628
|
+
impl: async (run, params) => {
|
|
1629
|
+
const uri = params.uri;
|
|
1630
|
+
if (!isNonBlankString(uri)) {
|
|
1631
|
+
return { error: "uri is required and must be a non-empty string" };
|
|
1632
|
+
}
|
|
1633
|
+
const trimmed = uri.trim();
|
|
1634
|
+
if (filesystemPathForUri(trimmed) !== null) {
|
|
1635
|
+
return {
|
|
1636
|
+
error: `read_media_bytes does not read filesystem paths (${trimmed}). Use read_file for a workspace file, or pass an asset:// URI.`
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
// A bare id is what an agent reaches for after reading `asset_id` off a
|
|
1640
|
+
// generation result; accept it rather than making that a failed round trip.
|
|
1641
|
+
const ref = trimmed.includes("://")
|
|
1642
|
+
? { uri: trimmed }
|
|
1643
|
+
: { uri: trimmed, asset_id: trimmed };
|
|
1644
|
+
try {
|
|
1645
|
+
const bytes = await loadMediaRefBytes(ref, run.context);
|
|
1646
|
+
if (!bytes) {
|
|
1647
|
+
return {
|
|
1648
|
+
error: `Could not read ${trimmed}. Pass the asset:// URI a generation returned (its asset_uri), or list_assets to find one.`
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1651
|
+
if (bytes.length > MAX_MEDIA_REF_BYTES) {
|
|
1652
|
+
return {
|
|
1653
|
+
error: `${trimmed} is ${bytes.length} bytes, over the ${MAX_MEDIA_REF_BYTES} byte limit`
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
return {
|
|
1657
|
+
uri: trimmed,
|
|
1658
|
+
size: bytes.length,
|
|
1659
|
+
mime_type: mimeForRef(ref, DEFAULT_MIME.document),
|
|
1660
|
+
content_base64: encodeMediaBase64(bytes)
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1663
|
+
catch (e) {
|
|
1664
|
+
return {
|
|
1665
|
+
error: `read_media_bytes failed: ${e instanceof Error ? e.message : String(e)}`
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
};
|
|
1670
|
+
/**
|
|
1671
|
+
* A real directory a host media binary can run in, plus the workspace it
|
|
1672
|
+
* belongs to.
|
|
1673
|
+
*
|
|
1674
|
+
* A local workspace *is* that directory, so the binary reads and writes the
|
|
1675
|
+
* user's files in place. A cloud workspace has no directory, so the run gets a
|
|
1676
|
+
* scratch one: inputs named in argv are staged into it beforehand
|
|
1677
|
+
* ({@link stageHostBinaryInputs}) and the output is read back out of it
|
|
1678
|
+
* afterwards ({@link persistWorkspaceFile}). Either way the binary sees plain
|
|
1679
|
+
* paths and needs no knowledge of where the workspace actually lives.
|
|
1680
|
+
*/
|
|
1681
|
+
async function hostBinaryRoot(context) {
|
|
1682
|
+
const workspace = context.workspace;
|
|
1683
|
+
if (!workspace) {
|
|
1684
|
+
return { error: "a workspace is required to run a host media binary" };
|
|
1685
|
+
}
|
|
1686
|
+
try {
|
|
1687
|
+
return { workspace, cwd: await workspace.scratchDir() };
|
|
1688
|
+
}
|
|
1689
|
+
catch (e) {
|
|
1690
|
+
return {
|
|
1691
|
+
error: `could not prepare a working directory: ${e instanceof Error ? e.message : String(e)}`
|
|
1692
|
+
};
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* Copy every argv path that names an existing workspace file into the scratch
|
|
1697
|
+
* directory, so the binary finds its inputs where it expects them.
|
|
1698
|
+
*
|
|
1699
|
+
* A no-op on a local workspace, where the scratch directory is the workspace.
|
|
1700
|
+
* Only whole arguments are staged: an input reaches ffmpeg as its own argv
|
|
1701
|
+
* entry (`-i clip.mp4`), and a path buried inside a filter token names an
|
|
1702
|
+
* output far more often than an input.
|
|
1703
|
+
*/
|
|
1704
|
+
async function stageHostBinaryInputs(workspace, argv) {
|
|
1705
|
+
if (workspace.localDir)
|
|
1706
|
+
return;
|
|
1707
|
+
for (const arg of argv) {
|
|
1708
|
+
if (!arg || arg.startsWith("-"))
|
|
1709
|
+
continue;
|
|
1710
|
+
try {
|
|
1711
|
+
if (await workspace.exists(arg))
|
|
1712
|
+
await workspace.materialize(arg);
|
|
1713
|
+
}
|
|
1714
|
+
catch {
|
|
1715
|
+
// Not a workspace path, or not readable — the binary reports it.
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
function stringArgs(raw) {
|
|
1720
|
+
if (!Array.isArray(raw) || raw.length === 0) {
|
|
1721
|
+
return { error: "args must be a non-empty array of strings" };
|
|
1722
|
+
}
|
|
1723
|
+
const args = [];
|
|
1724
|
+
for (const item of raw) {
|
|
1725
|
+
if (!isString(item)) {
|
|
1726
|
+
return { error: "args must be a non-empty array of strings" };
|
|
1727
|
+
}
|
|
1728
|
+
args.push(item);
|
|
1729
|
+
}
|
|
1730
|
+
return args;
|
|
1731
|
+
}
|
|
1732
|
+
/**
|
|
1733
|
+
* Take what the binary produced and put it in the workspace.
|
|
1734
|
+
*
|
|
1735
|
+
* The file is on disk either way — in the workspace folder on a local run, in
|
|
1736
|
+
* the scratch directory on a cloud one — so it is read from there and written
|
|
1737
|
+
* through `persistBinaryOutput`, which stores it in the workspace and (when
|
|
1738
|
+
* asked) as an asset.
|
|
1739
|
+
*/
|
|
1740
|
+
async function persistWorkspaceFile(context, workspace, relPath) {
|
|
1741
|
+
let abs;
|
|
1742
|
+
try {
|
|
1743
|
+
const root = workspace.localDir ?? (await workspace.scratchDir());
|
|
1744
|
+
abs = path.join(root, workspace.key(relPath));
|
|
1745
|
+
}
|
|
1746
|
+
catch (e) {
|
|
1747
|
+
return { persist_error: e instanceof Error ? e.message : String(e) };
|
|
1748
|
+
}
|
|
1749
|
+
try {
|
|
1750
|
+
const bytes = await readFile(abs);
|
|
1751
|
+
const persisted = await persistBinaryOutput(context, bytes, {
|
|
1752
|
+
outputFile: relPath,
|
|
1753
|
+
contentType: mimeFromFilename(relPath),
|
|
1754
|
+
uiPrefix: "media"
|
|
1755
|
+
});
|
|
1756
|
+
return { ...persisted };
|
|
1757
|
+
}
|
|
1758
|
+
catch (e) {
|
|
1759
|
+
return { persist_error: e instanceof Error ? e.message : String(e) };
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
/**
|
|
1763
|
+
* What a refused `://` in ffmpeg argv should do instead. The guard's default
|
|
1764
|
+
* says "stage it first" without saying how; here there is a parameter for it.
|
|
1765
|
+
*/
|
|
1766
|
+
const FFMPEG_REMEDY = 'Pass the ref in `inputs` instead — {"clip.mp4": "asset://<id>.mp4"} ' +
|
|
1767
|
+
"copies it into the workspace, then name `clip.mp4` in args.";
|
|
1768
|
+
/** The same remedy for `ffprobe`, whose one path argument replaces argv. */
|
|
1769
|
+
const FFPROBE_REMEDY = 'Pass the ref in `inputs` instead — {"clip.mp4": "asset://<id>.mp4"} ' +
|
|
1770
|
+
'copies it into the workspace, then set path to "clip.mp4".';
|
|
1771
|
+
/** Per-file limit for inline, temporary, and non-local staged inputs. */
|
|
1772
|
+
const MAX_STAGED_INPUT_BYTES = 100 * 1024 * 1024;
|
|
1773
|
+
/** Files one `inputs` bag may stage. */
|
|
1774
|
+
const MAX_STAGED_INPUTS = 8;
|
|
1775
|
+
/** Bytes one `inputs` bag may stage in total. */
|
|
1776
|
+
const MAX_STAGED_TOTAL_BYTES = 256 * 1024 * 1024;
|
|
1777
|
+
/**
|
|
1778
|
+
* Copy the refs in `inputs` into the workspace under the names the caller
|
|
1779
|
+
* gave them, so argv can name plain local files.
|
|
1780
|
+
*
|
|
1781
|
+
* ffmpeg opens local files only — a URL or an `asset://` URI in argv is
|
|
1782
|
+
* refused, and rightly so. But chat code has no workspace API of its own, so
|
|
1783
|
+
* before this there was no way to put an asset where ffmpeg could see it: the
|
|
1784
|
+
* capability was on the belt and unusable, and the refusal told the caller to
|
|
1785
|
+
* "download first" with nothing to download with. Staging is that missing
|
|
1786
|
+
* half, and it changes no boundary — the bytes are resolved host-side by the
|
|
1787
|
+
* same resolver `save_asset` uses, and every name still goes through
|
|
1788
|
+
* {@link confineArgvToWorkspace}.
|
|
1789
|
+
*/
|
|
1790
|
+
async function stageInputs(context, workspace, cwd, raw) {
|
|
1791
|
+
if (raw === undefined || raw === null)
|
|
1792
|
+
return { staged: {} };
|
|
1793
|
+
if (!isRecord(raw)) {
|
|
1794
|
+
return {
|
|
1795
|
+
error: 'inputs must be an object of {"<workspace-relative name>": "<asset:// URI, /api/storage/ key, or data: URI>"}'
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1798
|
+
const entries = Object.entries(raw);
|
|
1799
|
+
if (entries.length > MAX_STAGED_INPUTS) {
|
|
1800
|
+
return {
|
|
1801
|
+
error: `inputs stages at most ${MAX_STAGED_INPUTS} files; ${entries.length} were given.`
|
|
1802
|
+
};
|
|
1803
|
+
}
|
|
1804
|
+
const names = entries.map(([name]) => name);
|
|
1805
|
+
const refusal = await confineArgvToWorkspace(names, cwd);
|
|
1806
|
+
if (refusal)
|
|
1807
|
+
return refusal;
|
|
1808
|
+
const staged = {};
|
|
1809
|
+
let total = 0;
|
|
1810
|
+
const localAssetLimit = workspace.localDir
|
|
1811
|
+
? getMaxLocalUploadBytes()
|
|
1812
|
+
: undefined;
|
|
1813
|
+
const hasLocalAsset = localAssetLimit !== undefined && entries.some(([, ref]) => isNonBlankString(ref) && ref.trim().startsWith("asset://"));
|
|
1814
|
+
const totalLimit = hasLocalAsset
|
|
1815
|
+
? Math.max(MAX_STAGED_TOTAL_BYTES, localAssetLimit ?? 0)
|
|
1816
|
+
: MAX_STAGED_TOTAL_BYTES;
|
|
1817
|
+
for (const [name, ref] of entries) {
|
|
1818
|
+
if (!isNonBlankString(name)) {
|
|
1819
|
+
return { error: "inputs keys must be non-empty workspace paths." };
|
|
1820
|
+
}
|
|
1821
|
+
if (!isNonBlankString(ref)) {
|
|
1822
|
+
return {
|
|
1823
|
+
error: `inputs["${name}"] must be a string ref (asset:// URI, /api/storage/ key, or data: URI).`
|
|
1824
|
+
};
|
|
1825
|
+
}
|
|
1826
|
+
let bytes = null;
|
|
1827
|
+
let readError;
|
|
1828
|
+
try {
|
|
1829
|
+
bytes = await loadMediaRefBytes({ uri: ref.trim() }, context);
|
|
1830
|
+
}
|
|
1831
|
+
catch (e) {
|
|
1832
|
+
// Keep why. Naming only the accepted forms is useless to a caller who
|
|
1833
|
+
// already passed one — an unreachable bucket, a revoked credential and a
|
|
1834
|
+
// typo all arrive here, and only the first two are worth retrying. Told
|
|
1835
|
+
// just "pass an asset:// URI", a model re-sends the ref it has and then
|
|
1836
|
+
// starts guessing at URL shapes.
|
|
1837
|
+
readError = e instanceof Error ? e.message : String(e);
|
|
1838
|
+
}
|
|
1839
|
+
// Zero bytes is a failed read wearing a buffer, the same way it is in
|
|
1840
|
+
// `save_asset` — staging it would hand ffmpeg an empty file and the
|
|
1841
|
+
// failure would surface as an unhelpable decode error.
|
|
1842
|
+
if (!bytes || bytes.byteLength === 0) {
|
|
1843
|
+
return {
|
|
1844
|
+
error: `inputs["${name}"]: could not read ${ref}. ` +
|
|
1845
|
+
(readError
|
|
1846
|
+
? `Reading it failed: ${readError}. `
|
|
1847
|
+
: "It resolved to no bytes. ") +
|
|
1848
|
+
`Accepted: an asset:// URI, the /api/storage/ key a tool returned, ` +
|
|
1849
|
+
`or a data: URI.`
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
const inputLimit = localAssetLimit !== undefined && ref.trim().startsWith("asset://")
|
|
1853
|
+
? localAssetLimit
|
|
1854
|
+
: MAX_STAGED_INPUT_BYTES;
|
|
1855
|
+
if (bytes.byteLength > inputLimit) {
|
|
1856
|
+
return {
|
|
1857
|
+
error: `inputs["${name}"] is ${bytes.byteLength} bytes, over the ${inputLimit}-byte limit.`
|
|
1858
|
+
};
|
|
1859
|
+
}
|
|
1860
|
+
total += bytes.byteLength;
|
|
1861
|
+
if (total > totalLimit) {
|
|
1862
|
+
return {
|
|
1863
|
+
error: `inputs stages ${total} bytes, over the ${totalLimit}-byte total limit.`
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
// Through the workspace, so the staged input is durable and a cloud run
|
|
1867
|
+
// stages at all; then onto disk in `cwd`, because the binary opens a real
|
|
1868
|
+
// path. On a local workspace `materialize` hands back the file just
|
|
1869
|
+
// written, so this is one write, not two.
|
|
1870
|
+
try {
|
|
1871
|
+
await workspace.write(name, bytes);
|
|
1872
|
+
await workspace.materialize(name);
|
|
1873
|
+
}
|
|
1874
|
+
catch (e) {
|
|
1875
|
+
return {
|
|
1876
|
+
error: `inputs["${name}"] could not be staged: ${e instanceof Error ? e.message : String(e)}`
|
|
1877
|
+
};
|
|
1878
|
+
}
|
|
1879
|
+
staged[name] = bytes.byteLength;
|
|
1880
|
+
}
|
|
1881
|
+
return { staged };
|
|
1882
|
+
}
|
|
1883
|
+
const ffmpeg = {
|
|
1884
|
+
spec: ffmpegSpec,
|
|
1885
|
+
impl: async (run, params) => {
|
|
1886
|
+
const root = await hostBinaryRoot(run.context);
|
|
1887
|
+
if ("error" in root)
|
|
1888
|
+
return root;
|
|
1889
|
+
const { workspace, cwd } = root;
|
|
1890
|
+
const args = stringArgs(params["args"]);
|
|
1891
|
+
if ("error" in args)
|
|
1892
|
+
return args;
|
|
1893
|
+
const stagedResult = await stageInputs(run.context, workspace, cwd, params["inputs"]);
|
|
1894
|
+
if ("error" in stagedResult)
|
|
1895
|
+
return stagedResult;
|
|
1896
|
+
const outputFile = isNonBlankString(params["output_file"])
|
|
1897
|
+
? params["output_file"].trim()
|
|
1898
|
+
: "";
|
|
1899
|
+
const argv = [...args];
|
|
1900
|
+
if (outputFile && !argv.includes(outputFile)) {
|
|
1901
|
+
argv.push(outputFile);
|
|
1902
|
+
}
|
|
1903
|
+
const refusal = await confineArgvToWorkspace(argv, cwd, FFMPEG_REMEDY);
|
|
1904
|
+
if (refusal)
|
|
1905
|
+
return refusal;
|
|
1906
|
+
const hardened = hardenFfmpegArgv(argv);
|
|
1907
|
+
if ("error" in hardened)
|
|
1908
|
+
return hardened;
|
|
1909
|
+
const persistTarget = outputFile ||
|
|
1910
|
+
[...argv].reverse().find((item) => item && !item.startsWith("-")) ||
|
|
1911
|
+
"";
|
|
1912
|
+
const timeoutMs = clampTimeoutSeconds(params["timeout_seconds"], 180, 600) * 1000;
|
|
1913
|
+
const runOptions = { cwd, timeoutMs };
|
|
1914
|
+
// Only a known output path can be watched for size; without one the
|
|
1915
|
+
// wall clock and the capture cap are the run's bounds.
|
|
1916
|
+
if (persistTarget) {
|
|
1917
|
+
runOptions.artifactPath = persistTarget;
|
|
1918
|
+
}
|
|
1919
|
+
try {
|
|
1920
|
+
await stageHostBinaryInputs(workspace, hardened.argv);
|
|
1921
|
+
const result = await runHostBinary("ffmpeg", hardened.argv, runOptions);
|
|
1922
|
+
const persisted = result.exitCode === 0 && persistTarget
|
|
1923
|
+
? await persistWorkspaceFile(run.context, workspace, persistTarget)
|
|
1924
|
+
: undefined;
|
|
1925
|
+
const report = {
|
|
1926
|
+
success: result.exitCode === 0,
|
|
1927
|
+
stdout: result.stdout,
|
|
1928
|
+
stderr: result.stderr,
|
|
1929
|
+
exit_code: result.exitCode,
|
|
1930
|
+
...(persisted ?? {})
|
|
1931
|
+
};
|
|
1932
|
+
if (Object.keys(stagedResult.staged).length > 0) {
|
|
1933
|
+
report["staged"] = stagedResult.staged;
|
|
1934
|
+
}
|
|
1935
|
+
return report;
|
|
1936
|
+
}
|
|
1937
|
+
catch (e) {
|
|
1938
|
+
if (e instanceof HostBinaryMissingError) {
|
|
1939
|
+
return { error: e.message };
|
|
1940
|
+
}
|
|
1941
|
+
return {
|
|
1942
|
+
error: `ffmpeg failed: ${e instanceof Error ? e.message : String(e)}`
|
|
1943
|
+
};
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
};
|
|
1947
|
+
/**
|
|
1948
|
+
* What ffprobe reports as numbers, as numbers.
|
|
1949
|
+
*
|
|
1950
|
+
* ffprobe's JSON is all strings — `"duration": "8.000000"` — so arithmetic on
|
|
1951
|
+
* it silently produces `"8.000000".toFixed is not a function`, or worse, a
|
|
1952
|
+
* concatenation. The raw payload stays exactly as ffprobe wrote it; this is a
|
|
1953
|
+
* second, typed view of the four fields a caller actually plans a cut with.
|
|
1954
|
+
*/
|
|
1955
|
+
export function ffprobeSummary(parsed) {
|
|
1956
|
+
const format = isObjectLike(parsed["format"]) ? parsed["format"] : {};
|
|
1957
|
+
const streams = Array.isArray(parsed["streams"]) ? parsed["streams"] : [];
|
|
1958
|
+
const numeric = (value) => {
|
|
1959
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
1960
|
+
return Number.isFinite(n) ? n : null;
|
|
1961
|
+
};
|
|
1962
|
+
const ofKind = (kind) => streams.find((s) => isObjectLike(s) && s["codec_type"] === kind);
|
|
1963
|
+
const video = ofKind("video");
|
|
1964
|
+
const audio = ofKind("audio");
|
|
1965
|
+
const summary = {
|
|
1966
|
+
duration_seconds: numeric(format["duration"]) ?? numeric(video?.["duration"]),
|
|
1967
|
+
has_video: video !== undefined,
|
|
1968
|
+
has_audio: audio !== undefined
|
|
1969
|
+
};
|
|
1970
|
+
if (video) {
|
|
1971
|
+
summary["width"] = numeric(video["width"]);
|
|
1972
|
+
summary["height"] = numeric(video["height"]);
|
|
1973
|
+
}
|
|
1974
|
+
return summary;
|
|
1975
|
+
}
|
|
1976
|
+
/**
|
|
1977
|
+
* Refs `ffprobe` stages for itself, rather than refusing.
|
|
1978
|
+
*
|
|
1979
|
+
* These are the forms NodeTool's own tools hand back, so a caller probing a
|
|
1980
|
+
* clip it just generated is passing the string it was given. An http(s) URL is
|
|
1981
|
+
* not here: fetching one is egress, and egress belongs to the surfaces that
|
|
1982
|
+
* declare it.
|
|
1983
|
+
*/
|
|
1984
|
+
function isStageableProbeRef(value) {
|
|
1985
|
+
return (value.startsWith("asset://") ||
|
|
1986
|
+
value.startsWith("/api/storage/") ||
|
|
1987
|
+
value.startsWith("data:"));
|
|
1988
|
+
}
|
|
1989
|
+
/** A workspace file name for a staged probe target, from the ref itself. */
|
|
1990
|
+
function probeStagingName(ref) {
|
|
1991
|
+
if (ref.startsWith("data:"))
|
|
1992
|
+
return "ffprobe-input/input";
|
|
1993
|
+
const tail = ref.split("/").pop() ?? "input";
|
|
1994
|
+
const safe = tail.replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 64);
|
|
1995
|
+
return `ffprobe-input/${safe || "input"}`;
|
|
1996
|
+
}
|
|
1997
|
+
/**
|
|
1998
|
+
* ffprobe with an argv NodeTool writes, not the caller.
|
|
1999
|
+
*
|
|
2000
|
+
* Everything a caller can say is one workspace path, so the whole boundary is
|
|
2001
|
+
* the confinement check — there is no flag surface to guard, and no way to ask
|
|
2002
|
+
* ffprobe to open a socket. `inputs` stages assets under workspace names the
|
|
2003
|
+
* same way `ffmpeg`'s does: without it the two halves of one loop disagreed,
|
|
2004
|
+
* and a caller who had just staged a clip for ffmpeg could not ask ffprobe how
|
|
2005
|
+
* long it was without staging it a second time through a no-op ffmpeg copy.
|
|
2006
|
+
*/
|
|
2007
|
+
const ffprobe = {
|
|
2008
|
+
spec: ffprobeSpec,
|
|
2009
|
+
impl: async (run, params) => {
|
|
2010
|
+
const root = await hostBinaryRoot(run.context);
|
|
2011
|
+
if ("error" in root)
|
|
2012
|
+
return root;
|
|
2013
|
+
const { workspace, cwd } = root;
|
|
2014
|
+
const target = params["path"];
|
|
2015
|
+
if (!isNonBlankString(target)) {
|
|
2016
|
+
return { error: "path is required" };
|
|
2017
|
+
}
|
|
2018
|
+
const requested = target.trim();
|
|
2019
|
+
// ffprobe's whole argv is this one path, so an `asset://` here can only
|
|
2020
|
+
// mean "probe that": there is no flag to smuggle and nothing else to
|
|
2021
|
+
// confine. Refusing it made the two halves of one loop disagree — the
|
|
2022
|
+
// guest's own `video.info(asset://…)` reads a ref happily — and a caller
|
|
2023
|
+
// who just wanted a duration had to stage the file by hand first.
|
|
2024
|
+
const autoStaged = isStageableProbeRef(requested);
|
|
2025
|
+
const probePath = autoStaged ? probeStagingName(requested) : requested;
|
|
2026
|
+
let toStage = params["inputs"];
|
|
2027
|
+
if (autoStaged) {
|
|
2028
|
+
const extra = isRecord(toStage) ? toStage : {};
|
|
2029
|
+
toStage = { ...extra, [probePath]: requested };
|
|
2030
|
+
}
|
|
2031
|
+
const stagedResult = await stageInputs(run.context, workspace, cwd, toStage);
|
|
2032
|
+
if ("error" in stagedResult)
|
|
2033
|
+
return stagedResult;
|
|
2034
|
+
const refusal = await confineArgvToWorkspace([probePath], cwd, FFPROBE_REMEDY);
|
|
2035
|
+
if (refusal)
|
|
2036
|
+
return refusal;
|
|
2037
|
+
await stageHostBinaryInputs(workspace, [probePath]);
|
|
2038
|
+
const timeoutMs = clampTimeoutSeconds(params["timeout_seconds"], 30, 120) * 1000;
|
|
2039
|
+
try {
|
|
2040
|
+
const result = await runHostBinary("ffprobe", [
|
|
2041
|
+
"-v",
|
|
2042
|
+
"error",
|
|
2043
|
+
"-print_format",
|
|
2044
|
+
"json",
|
|
2045
|
+
"-show_format",
|
|
2046
|
+
"-show_streams",
|
|
2047
|
+
probePath
|
|
2048
|
+
], { cwd, timeoutMs });
|
|
2049
|
+
if (result.exitCode !== 0) {
|
|
2050
|
+
return {
|
|
2051
|
+
error: `ffprobe failed: ${result.stderr.trim() || `exit ${result.exitCode}`}`
|
|
2052
|
+
};
|
|
2053
|
+
}
|
|
2054
|
+
const parsed = JSON.parse(result.stdout);
|
|
2055
|
+
if (!isObjectLike(parsed)) {
|
|
2056
|
+
return { error: "ffprobe returned no readable JSON" };
|
|
2057
|
+
}
|
|
2058
|
+
const report = {
|
|
2059
|
+
path: requested,
|
|
2060
|
+
...parsed,
|
|
2061
|
+
summary: ffprobeSummary(parsed)
|
|
2062
|
+
};
|
|
2063
|
+
if (Object.keys(stagedResult.staged).length > 0) {
|
|
2064
|
+
report["staged"] = stagedResult.staged;
|
|
2065
|
+
}
|
|
2066
|
+
return report;
|
|
2067
|
+
}
|
|
2068
|
+
catch (e) {
|
|
2069
|
+
if (e instanceof HostBinaryMissingError) {
|
|
2070
|
+
return { error: e.message };
|
|
2071
|
+
}
|
|
2072
|
+
return {
|
|
2073
|
+
error: `ffprobe failed: ${e instanceof Error ? e.message : String(e)}`
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
};
|
|
2078
|
+
const DEFAULT_YT_DLP_OUTPUT = "downloads/yt-dlp/%(id)s.%(ext)s";
|
|
2079
|
+
const ytDlp = {
|
|
2080
|
+
spec: ytDlpSpec,
|
|
2081
|
+
impl: async (run, params) => {
|
|
2082
|
+
// The cloud profile leaves this off every belt, so a model never sees it.
|
|
2083
|
+
// A host that resolves the capability by name still lands here.
|
|
2084
|
+
if (!isYtDlpEnabled()) {
|
|
2085
|
+
return { error: "yt_dlp is not available on this deployment" };
|
|
2086
|
+
}
|
|
2087
|
+
const root = await hostBinaryRoot(run.context);
|
|
2088
|
+
if ("error" in root)
|
|
2089
|
+
return root;
|
|
2090
|
+
const { workspace, cwd } = root;
|
|
2091
|
+
const url = params["url"];
|
|
2092
|
+
if (!isNonBlankString(url)) {
|
|
2093
|
+
return { error: "url is required" };
|
|
2094
|
+
}
|
|
2095
|
+
// The downloader opens its own sockets from inside the server, so an
|
|
2096
|
+
// http(s) check alone leaves the metadata service and every internal
|
|
2097
|
+
// host reachable. Same guard the sandbox fetch bridge uses, plus the
|
|
2098
|
+
// resolution step a hostname needs.
|
|
2099
|
+
try {
|
|
2100
|
+
assertFetchUrlAllowed(url);
|
|
2101
|
+
await assertResolvedHostAllowed(url, "yt_dlp");
|
|
2102
|
+
}
|
|
2103
|
+
catch (e) {
|
|
2104
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
2105
|
+
return { error: message.replace(/^fetch: /, "yt_dlp: ") };
|
|
2106
|
+
}
|
|
2107
|
+
const outputFile = isNonBlankString(params["output_file"])
|
|
2108
|
+
? params["output_file"].trim()
|
|
2109
|
+
: DEFAULT_YT_DLP_OUTPUT;
|
|
2110
|
+
const format = isNonBlankString(params["format"])
|
|
2111
|
+
? params["format"].trim()
|
|
2112
|
+
: "";
|
|
2113
|
+
const timeoutMs = clampTimeoutSeconds(params["timeout_seconds"], 300, 900) * 1000;
|
|
2114
|
+
// The template is the caller's, so it escapes the workspace as easily as
|
|
2115
|
+
// an ffmpeg path does. `format` reaches yt-dlp as a selector, never a path.
|
|
2116
|
+
const refusal = await confineArgvToWorkspace([outputFile], cwd);
|
|
2117
|
+
if (refusal)
|
|
2118
|
+
return refusal;
|
|
2119
|
+
const flagLike = refuseFlagLikeValue(outputFile, "output_file") ??
|
|
2120
|
+
(format ? refuseFlagLikeValue(format, "format") : undefined);
|
|
2121
|
+
if (flagLike)
|
|
2122
|
+
return flagLike;
|
|
2123
|
+
const outDir = path.dirname(outputFile);
|
|
2124
|
+
if (outDir && outDir !== ".") {
|
|
2125
|
+
try {
|
|
2126
|
+
await mkdir(path.join(cwd, outDir), { recursive: true });
|
|
2127
|
+
}
|
|
2128
|
+
catch (e) {
|
|
2129
|
+
return {
|
|
2130
|
+
error: `could not create output directory: ${e instanceof Error ? e.message : String(e)}`
|
|
2131
|
+
};
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
const download = { url, outputFile };
|
|
2135
|
+
if (format) {
|
|
2136
|
+
download.format = format;
|
|
2137
|
+
}
|
|
2138
|
+
const argv = buildYtDlpArgv(download);
|
|
2139
|
+
try {
|
|
2140
|
+
const result = await runHostBinary("yt-dlp", argv, {
|
|
2141
|
+
cwd,
|
|
2142
|
+
timeoutMs
|
|
2143
|
+
});
|
|
2144
|
+
const printed = result.stdout.trim().split("\n").filter(Boolean).at(-1);
|
|
2145
|
+
// `--print after_move:filepath` names the finished file. Nothing printed
|
|
2146
|
+
// on a clean exit means nothing was written — which is what an aborted
|
|
2147
|
+
// over-cap download looks like, since `--print` silences the reason.
|
|
2148
|
+
if (result.exitCode === 0 && !printed) {
|
|
2149
|
+
return {
|
|
2150
|
+
success: false,
|
|
2151
|
+
url,
|
|
2152
|
+
error: `yt-dlp wrote no file. The download may have passed the ` +
|
|
2153
|
+
`${MAX_DOWNLOAD_BYTES}-byte limit, or the URL carried nothing to ` +
|
|
2154
|
+
`download.`,
|
|
2155
|
+
stdout: result.stdout,
|
|
2156
|
+
stderr: result.stderr,
|
|
2157
|
+
exit_code: result.exitCode
|
|
2158
|
+
};
|
|
2159
|
+
}
|
|
2160
|
+
const produced = printed && !printed.startsWith("http")
|
|
2161
|
+
? path.isAbsolute(printed)
|
|
2162
|
+
? path.relative(cwd, printed)
|
|
2163
|
+
: printed
|
|
2164
|
+
: outputFile.includes("%(")
|
|
2165
|
+
? ""
|
|
2166
|
+
: outputFile;
|
|
2167
|
+
const persisted = result.exitCode === 0 && produced
|
|
2168
|
+
? await persistWorkspaceFile(run.context, workspace, produced)
|
|
2169
|
+
: undefined;
|
|
2170
|
+
return {
|
|
2171
|
+
success: result.exitCode === 0,
|
|
2172
|
+
url,
|
|
2173
|
+
output_file: produced || outputFile,
|
|
2174
|
+
stdout: result.stdout,
|
|
2175
|
+
stderr: result.stderr,
|
|
2176
|
+
exit_code: result.exitCode,
|
|
2177
|
+
...(persisted ?? {})
|
|
2178
|
+
};
|
|
2179
|
+
}
|
|
2180
|
+
catch (e) {
|
|
2181
|
+
if (e instanceof HostBinaryMissingError) {
|
|
2182
|
+
return { error: e.message };
|
|
2183
|
+
}
|
|
2184
|
+
return {
|
|
2185
|
+
error: `yt-dlp failed: ${e instanceof Error ? e.message : String(e)}`
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
};
|
|
2190
|
+
/** Every media capability, in the order `getAllMcpTools` offered them. */
|
|
2191
|
+
export const MEDIA_CAPABILITIES = [
|
|
2192
|
+
generateText,
|
|
2193
|
+
generateImage,
|
|
2194
|
+
editImage,
|
|
2195
|
+
segmentImage,
|
|
2196
|
+
generateVideo,
|
|
2197
|
+
animateImage,
|
|
2198
|
+
videoFromReferences,
|
|
2199
|
+
generateSpeech,
|
|
2200
|
+
generateMusic,
|
|
2201
|
+
transcribeAudio,
|
|
2202
|
+
embedText,
|
|
2203
|
+
readMediaBytes,
|
|
2204
|
+
critiqueImage,
|
|
2205
|
+
compareImages,
|
|
2206
|
+
scoreImageAdherence,
|
|
2207
|
+
understandVideo,
|
|
2208
|
+
ffmpeg,
|
|
2209
|
+
ffprobe,
|
|
2210
|
+
ytDlp
|
|
2211
|
+
];
|
|
2212
|
+
export const module = {
|
|
2213
|
+
module: "media",
|
|
2214
|
+
exports: MEDIA_CAPABILITIES
|
|
2215
|
+
};
|
|
2216
|
+
export { generateText, generateImage, editImage, segmentImage, generateVideo, animateImage, videoFromReferences, generateSpeech, generateMusic, transcribeAudio, embedText, readMediaBytes, critiqueImage, compareImages, scoreImageAdherence, understandVideo, ffmpeg, ffprobe, ytDlp };
|
|
2217
|
+
//# sourceMappingURL=media.js.map
|