@nodetool-ai/runtime 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 +29 -0
- package/dist/.nodetool-build-stamp +1 -0
- package/dist/agent-memory.d.ts +118 -0
- package/dist/agent-memory.d.ts.map +1 -0
- package/dist/agent-memory.js +186 -0
- package/dist/agent-memory.js.map +1 -0
- package/dist/async-local-storage.d.ts +20 -0
- package/dist/async-local-storage.d.ts.map +1 -0
- package/dist/async-local-storage.js +28 -0
- package/dist/async-local-storage.js.map +1 -0
- package/dist/blender-executor.d.ts +93 -0
- package/dist/blender-executor.d.ts.map +1 -0
- package/dist/blender-executor.js +294 -0
- package/dist/blender-executor.js.map +1 -0
- package/dist/comfy-executor.d.ts +23 -1
- package/dist/comfy-executor.d.ts.map +1 -1
- package/dist/comfy-executor.js +234 -55
- package/dist/comfy-executor.js.map +1 -1
- package/dist/context-packer.d.ts +1 -1
- package/dist/context-packer.d.ts.map +1 -1
- package/dist/context-packer.js +23 -25
- package/dist/context-packer.js.map +1 -1
- package/dist/context.d.ts +954 -127
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +2424 -513
- package/dist/context.js.map +1 -1
- package/dist/cost-reconciler.d.ts +32 -0
- package/dist/cost-reconciler.d.ts.map +1 -0
- package/dist/cost-reconciler.js +21 -0
- package/dist/cost-reconciler.js.map +1 -0
- package/dist/entities.d.ts +33 -0
- package/dist/entities.d.ts.map +1 -0
- package/dist/entities.js +43 -0
- package/dist/entities.js.map +1 -0
- package/dist/external-media-fetch.d.ts +29 -0
- package/dist/external-media-fetch.d.ts.map +1 -0
- package/dist/external-media-fetch.js +38 -0
- package/dist/external-media-fetch.js.map +1 -0
- package/dist/generation-receipt.d.ts +86 -0
- package/dist/generation-receipt.d.ts.map +1 -0
- package/dist/generation-receipt.js +137 -0
- package/dist/generation-receipt.js.map +1 -0
- package/dist/generation-registry.d.ts +67 -0
- package/dist/generation-registry.d.ts.map +1 -0
- package/dist/generation-registry.js +126 -0
- package/dist/generation-registry.js.map +1 -0
- package/dist/google/client.d.ts +196 -0
- package/dist/google/client.d.ts.map +1 -0
- package/dist/google/client.js +396 -0
- package/dist/google/client.js.map +1 -0
- package/dist/google/index.d.ts +3 -0
- package/dist/google/index.d.ts.map +1 -0
- package/dist/google/index.js +3 -0
- package/dist/google/index.js.map +1 -0
- package/dist/google/token.d.ts +15 -0
- package/dist/google/token.d.ts.map +1 -0
- package/dist/google/token.js +24 -0
- package/dist/google/token.js.map +1 -0
- package/dist/host-binaries.d.ts +106 -0
- package/dist/host-binaries.d.ts.map +1 -0
- package/dist/host-binaries.js +344 -0
- package/dist/host-binaries.js.map +1 -0
- package/dist/image-codec.d.ts +74 -0
- package/dist/image-codec.d.ts.map +1 -0
- package/dist/image-codec.js +273 -0
- package/dist/image-codec.js.map +1 -0
- package/dist/index.d.ts +56 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -4
- package/dist/index.js.map +1 -1
- package/dist/invocation-account.d.ts +43 -0
- package/dist/invocation-account.d.ts.map +1 -0
- package/dist/invocation-account.js +60 -0
- package/dist/invocation-account.js.map +1 -0
- package/dist/media-ref-bytes.d.ts +19 -0
- package/dist/media-ref-bytes.d.ts.map +1 -0
- package/dist/media-ref-bytes.js +181 -0
- package/dist/media-ref-bytes.js.map +1 -0
- package/dist/node-executor.d.ts +113 -2
- package/dist/node-executor.d.ts.map +1 -1
- package/dist/permission-gate.d.ts +152 -0
- package/dist/permission-gate.d.ts.map +1 -0
- package/dist/permission-gate.js +87 -0
- package/dist/permission-gate.js.map +1 -0
- package/dist/prefixed-storage-adapter.d.ts +33 -0
- package/dist/prefixed-storage-adapter.d.ts.map +1 -0
- package/dist/prefixed-storage-adapter.js +70 -0
- package/dist/prefixed-storage-adapter.js.map +1 -0
- package/dist/prompt-asset-refs.d.ts +222 -0
- package/dist/prompt-asset-refs.d.ts.map +1 -0
- package/dist/prompt-asset-refs.js +751 -0
- package/dist/prompt-asset-refs.js.map +1 -0
- package/dist/provider-cache.d.ts +3 -0
- package/dist/provider-cache.d.ts.map +1 -0
- package/dist/provider-cache.js +8 -0
- package/dist/provider-cache.js.map +1 -0
- package/dist/providers/aki-provider.d.ts +33 -10
- package/dist/providers/aki-provider.d.ts.map +1 -1
- package/dist/providers/aki-provider.js +84 -77
- package/dist/providers/aki-provider.js.map +1 -1
- package/dist/providers/alibaba-provider.d.ts +39 -0
- package/dist/providers/alibaba-provider.d.ts.map +1 -0
- package/dist/providers/alibaba-provider.js +86 -0
- package/dist/providers/alibaba-provider.js.map +1 -0
- package/dist/providers/anthropic-provider.d.ts +52 -3
- package/dist/providers/anthropic-provider.d.ts.map +1 -1
- package/dist/providers/anthropic-provider.js +1020 -338
- package/dist/providers/anthropic-provider.js.map +1 -1
- package/dist/providers/atlascloud-provider.d.ts +101 -0
- package/dist/providers/atlascloud-provider.d.ts.map +1 -0
- package/dist/providers/atlascloud-provider.js +1009 -0
- package/dist/providers/atlascloud-provider.js.map +1 -0
- package/dist/providers/atlascloud-transport.d.ts +100 -0
- package/dist/providers/atlascloud-transport.d.ts.map +1 -0
- package/dist/providers/atlascloud-transport.js +364 -0
- package/dist/providers/atlascloud-transport.js.map +1 -0
- package/dist/providers/atlascloud-webhook-registry.d.ts +35 -0
- package/dist/providers/atlascloud-webhook-registry.d.ts.map +1 -0
- package/dist/providers/atlascloud-webhook-registry.js +104 -0
- package/dist/providers/atlascloud-webhook-registry.js.map +1 -0
- package/dist/providers/audio-mime.d.ts +11 -0
- package/dist/providers/audio-mime.d.ts.map +1 -0
- package/dist/providers/audio-mime.js +46 -0
- package/dist/providers/audio-mime.js.map +1 -0
- package/dist/providers/base-provider.d.ts +481 -24
- package/dist/providers/base-provider.d.ts.map +1 -1
- package/dist/providers/base-provider.js +1259 -42
- package/dist/providers/base-provider.js.map +1 -1
- package/dist/providers/cassette-provider.d.ts +217 -0
- package/dist/providers/cassette-provider.d.ts.map +1 -0
- package/dist/providers/cassette-provider.js +502 -0
- package/dist/providers/cassette-provider.js.map +1 -0
- package/dist/providers/cerebras-provider.d.ts +6 -12
- package/dist/providers/cerebras-provider.d.ts.map +1 -1
- package/dist/providers/cerebras-provider.js +8 -33
- package/dist/providers/cerebras-provider.js.map +1 -1
- package/dist/providers/claude-agent-provider.d.ts +131 -68
- package/dist/providers/claude-agent-provider.d.ts.map +1 -1
- package/dist/providers/claude-agent-provider.js +1095 -515
- package/dist/providers/claude-agent-provider.js.map +1 -1
- package/dist/providers/codex-provider.d.ts +82 -0
- package/dist/providers/codex-provider.d.ts.map +1 -0
- package/dist/providers/codex-provider.js +492 -0
- package/dist/providers/codex-provider.js.map +1 -0
- package/dist/providers/cohere-provider.d.ts +5 -2
- package/dist/providers/cohere-provider.d.ts.map +1 -1
- package/dist/providers/cohere-provider.js +9 -2
- package/dist/providers/cohere-provider.js.map +1 -1
- package/dist/providers/comfy-cloud-provider.d.ts +30 -0
- package/dist/providers/comfy-cloud-provider.d.ts.map +1 -0
- package/dist/providers/comfy-cloud-provider.js +42 -0
- package/dist/providers/comfy-cloud-provider.js.map +1 -0
- package/dist/providers/content-filter.d.ts +46 -0
- package/dist/providers/content-filter.d.ts.map +1 -0
- package/dist/providers/content-filter.js +92 -0
- package/dist/providers/content-filter.js.map +1 -0
- package/dist/providers/context-exceeded.d.ts +37 -0
- package/dist/providers/context-exceeded.d.ts.map +1 -0
- package/dist/providers/context-exceeded.js +114 -0
- package/dist/providers/context-exceeded.js.map +1 -0
- package/dist/providers/context-window.d.ts +44 -0
- package/dist/providers/context-window.d.ts.map +1 -0
- package/dist/providers/context-window.js +145 -0
- package/dist/providers/context-window.js.map +1 -0
- package/dist/providers/contract/index.d.ts +4 -0
- package/dist/providers/contract/index.d.ts.map +1 -0
- package/dist/providers/contract/index.js +4 -0
- package/dist/providers/contract/index.js.map +1 -0
- package/dist/providers/contract/probe-manifest.d.ts +75 -0
- package/dist/providers/contract/probe-manifest.d.ts.map +1 -0
- package/dist/providers/contract/probe-manifest.js +379 -0
- package/dist/providers/contract/probe-manifest.js.map +1 -0
- package/dist/providers/contract/probe-runner.d.ts +57 -0
- package/dist/providers/contract/probe-runner.d.ts.map +1 -0
- package/dist/providers/contract/probe-runner.js +180 -0
- package/dist/providers/contract/probe-runner.js.map +1 -0
- package/dist/providers/contract/redact.d.ts +29 -0
- package/dist/providers/contract/redact.d.ts.map +1 -0
- package/dist/providers/contract/redact.js +113 -0
- package/dist/providers/contract/redact.js.map +1 -0
- package/dist/providers/core-tools.d.ts +74 -0
- package/dist/providers/core-tools.d.ts.map +1 -0
- package/dist/providers/core-tools.js +127 -0
- package/dist/providers/core-tools.js.map +1 -0
- package/dist/providers/cost-calculator.d.ts +69 -50
- package/dist/providers/cost-calculator.d.ts.map +1 -1
- package/dist/providers/cost-calculator.js +207 -397
- package/dist/providers/cost-calculator.js.map +1 -1
- package/dist/providers/credential-check.d.ts +45 -0
- package/dist/providers/credential-check.d.ts.map +1 -0
- package/dist/providers/credential-check.js +159 -0
- package/dist/providers/credential-check.js.map +1 -0
- package/dist/providers/custom-model-kinds.d.ts +33 -0
- package/dist/providers/custom-model-kinds.d.ts.map +1 -0
- package/dist/providers/custom-model-kinds.js +96 -0
- package/dist/providers/custom-model-kinds.js.map +1 -0
- package/dist/providers/custom-openai-provider.d.ts +81 -0
- package/dist/providers/custom-openai-provider.d.ts.map +1 -0
- package/dist/providers/custom-openai-provider.js +182 -0
- package/dist/providers/custom-openai-provider.js.map +1 -0
- package/dist/providers/custom-provider-registry.d.ts +19 -0
- package/dist/providers/custom-provider-registry.d.ts.map +1 -0
- package/dist/providers/custom-provider-registry.js +52 -0
- package/dist/providers/custom-provider-registry.js.map +1 -0
- package/dist/providers/deepseek-provider.d.ts +8 -14
- package/dist/providers/deepseek-provider.d.ts.map +1 -1
- package/dist/providers/deepseek-provider.js +6 -35
- package/dist/providers/deepseek-provider.js.map +1 -1
- package/dist/providers/defaults.d.ts +12 -0
- package/dist/providers/defaults.d.ts.map +1 -0
- package/dist/providers/defaults.js +12 -0
- package/dist/providers/defaults.js.map +1 -0
- package/dist/providers/elevenlabs-provider.d.ts +49 -0
- package/dist/providers/elevenlabs-provider.d.ts.map +1 -0
- package/dist/providers/elevenlabs-provider.js +142 -0
- package/dist/providers/elevenlabs-provider.js.map +1 -0
- package/dist/providers/entity-references.d.ts +31 -0
- package/dist/providers/entity-references.d.ts.map +1 -0
- package/dist/providers/entity-references.js +113 -0
- package/dist/providers/entity-references.js.map +1 -0
- package/dist/providers/evolink-provider.d.ts +38 -0
- package/dist/providers/evolink-provider.d.ts.map +1 -0
- package/dist/providers/evolink-provider.js +304 -0
- package/dist/providers/evolink-provider.js.map +1 -0
- package/dist/providers/fake-provider.d.ts +72 -1
- package/dist/providers/fake-provider.d.ts.map +1 -1
- package/dist/providers/fake-provider.js +203 -1
- package/dist/providers/fake-provider.js.map +1 -1
- package/dist/providers/fal-generations.d.ts +106 -0
- package/dist/providers/fal-generations.d.ts.map +1 -0
- package/dist/providers/fal-generations.js +286 -0
- package/dist/providers/fal-generations.js.map +1 -0
- package/dist/providers/fal-provider.d.ts +171 -7
- package/dist/providers/fal-provider.d.ts.map +1 -1
- package/dist/providers/fal-provider.js +1369 -64
- package/dist/providers/fal-provider.js.map +1 -1
- package/dist/providers/fal-queue.d.ts +47 -0
- package/dist/providers/fal-queue.d.ts.map +1 -0
- package/dist/providers/fal-queue.js +231 -0
- package/dist/providers/fal-queue.js.map +1 -0
- package/dist/providers/gemini-provider.d.ts +148 -8
- package/dist/providers/gemini-provider.d.ts.map +1 -1
- package/dist/providers/gemini-provider.js +1500 -316
- package/dist/providers/gemini-provider.js.map +1 -1
- package/dist/providers/gmi-provider.d.ts +21 -0
- package/dist/providers/gmi-provider.d.ts.map +1 -0
- package/dist/providers/gmi-provider.js +34 -0
- package/dist/providers/gmi-provider.js.map +1 -0
- package/dist/providers/gpt-image-size.d.ts +3 -0
- package/dist/providers/gpt-image-size.d.ts.map +1 -0
- package/dist/providers/gpt-image-size.js +37 -0
- package/dist/providers/gpt-image-size.js.map +1 -0
- package/dist/providers/groq-provider.d.ts +9 -12
- package/dist/providers/groq-provider.d.ts.map +1 -1
- package/dist/providers/groq-provider.js +19 -33
- package/dist/providers/groq-provider.js.map +1 -1
- package/dist/providers/groq-request.d.ts +38 -0
- package/dist/providers/groq-request.d.ts.map +1 -0
- package/dist/providers/groq-request.js +138 -0
- package/dist/providers/groq-request.js.map +1 -0
- package/dist/providers/higgsfield-provider.d.ts +30 -0
- package/dist/providers/higgsfield-provider.d.ts.map +1 -0
- package/dist/providers/higgsfield-provider.js +131 -0
- package/dist/providers/higgsfield-provider.js.map +1 -0
- package/dist/providers/higgsfield-transport.d.ts +106 -0
- package/dist/providers/higgsfield-transport.d.ts.map +1 -0
- package/dist/providers/higgsfield-transport.js +182 -0
- package/dist/providers/higgsfield-transport.js.map +1 -0
- package/dist/providers/http-transport.d.ts +74 -0
- package/dist/providers/http-transport.d.ts.map +1 -0
- package/dist/providers/http-transport.js +152 -0
- package/dist/providers/http-transport.js.map +1 -0
- package/dist/providers/huggingface-provider.d.ts +71 -3
- package/dist/providers/huggingface-provider.d.ts.map +1 -1
- package/dist/providers/huggingface-provider.js +230 -34
- package/dist/providers/huggingface-provider.js.map +1 -1
- package/dist/providers/image-mime.d.ts +39 -0
- package/dist/providers/image-mime.d.ts.map +1 -0
- package/dist/providers/image-mime.js +111 -0
- package/dist/providers/image-mime.js.map +1 -0
- package/dist/providers/image-ref.d.ts +21 -0
- package/dist/providers/image-ref.d.ts.map +1 -0
- package/dist/providers/image-ref.js +44 -0
- package/dist/providers/image-ref.js.map +1 -0
- package/dist/providers/index.d.ts +84 -8
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +239 -56
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/jina-provider.d.ts +10 -2
- package/dist/providers/jina-provider.d.ts.map +1 -1
- package/dist/providers/jina-provider.js +16 -7
- package/dist/providers/jina-provider.js.map +1 -1
- package/dist/providers/kie-provider.d.ts +170 -9
- package/dist/providers/kie-provider.d.ts.map +1 -1
- package/dist/providers/kie-provider.js +1176 -228
- package/dist/providers/kie-provider.js.map +1 -1
- package/dist/providers/kie-webhook-registry.d.ts +28 -0
- package/dist/providers/kie-webhook-registry.d.ts.map +1 -0
- package/dist/providers/kie-webhook-registry.js +91 -0
- package/dist/providers/kie-webhook-registry.js.map +1 -0
- package/dist/providers/llama-provider.d.ts +21 -37
- package/dist/providers/llama-provider.d.ts.map +1 -1
- package/dist/providers/llama-provider.js +43 -354
- package/dist/providers/llama-provider.js.map +1 -1
- package/dist/providers/lmstudio-provider.d.ts +4 -7
- package/dist/providers/lmstudio-provider.d.ts.map +1 -1
- package/dist/providers/lmstudio-provider.js +24 -15
- package/dist/providers/lmstudio-provider.js.map +1 -1
- package/dist/providers/manifest-models.d.ts +341 -1
- package/dist/providers/manifest-models.d.ts.map +1 -1
- package/dist/providers/manifest-models.js +1106 -22
- package/dist/providers/manifest-models.js.map +1 -1
- package/dist/providers/media-mime.d.ts +14 -0
- package/dist/providers/media-mime.d.ts.map +1 -0
- package/dist/providers/media-mime.js +35 -0
- package/dist/providers/media-mime.js.map +1 -0
- package/dist/providers/meshy-provider.d.ts +14 -1
- package/dist/providers/meshy-provider.d.ts.map +1 -1
- package/dist/providers/meshy-provider.js +76 -46
- package/dist/providers/meshy-provider.js.map +1 -1
- package/dist/providers/meta-provider.d.ts +22 -0
- package/dist/providers/meta-provider.d.ts.map +1 -0
- package/dist/providers/meta-provider.js +54 -0
- package/dist/providers/meta-provider.js.map +1 -0
- package/dist/providers/minimax-provider.d.ts +25 -18
- package/dist/providers/minimax-provider.d.ts.map +1 -1
- package/dist/providers/minimax-provider.js +211 -72
- package/dist/providers/minimax-provider.js.map +1 -1
- package/dist/providers/mistral-provider.d.ts +6 -12
- package/dist/providers/mistral-provider.d.ts.map +1 -1
- package/dist/providers/mistral-provider.js +10 -34
- package/dist/providers/mistral-provider.js.map +1 -1
- package/dist/providers/moonshot-provider.d.ts +11 -15
- package/dist/providers/moonshot-provider.d.ts.map +1 -1
- package/dist/providers/moonshot-provider.js +33 -23
- package/dist/providers/moonshot-provider.js.map +1 -1
- package/dist/providers/node-llama-cpp-provider.d.ts +98 -0
- package/dist/providers/node-llama-cpp-provider.d.ts.map +1 -0
- package/dist/providers/node-llama-cpp-provider.js +479 -0
- package/dist/providers/node-llama-cpp-provider.js.map +1 -0
- package/dist/providers/nodetool-provider.d.ts +49 -0
- package/dist/providers/nodetool-provider.d.ts.map +1 -0
- package/dist/providers/nodetool-provider.js +224 -0
- package/dist/providers/nodetool-provider.js.map +1 -0
- package/dist/providers/oauth/browser-launcher.d.ts +23 -0
- package/dist/providers/oauth/browser-launcher.d.ts.map +1 -0
- package/dist/providers/oauth/browser-launcher.js +45 -0
- package/dist/providers/oauth/browser-launcher.js.map +1 -0
- package/dist/providers/oauth/claude-code-credentials.d.ts +74 -0
- package/dist/providers/oauth/claude-code-credentials.d.ts.map +1 -0
- package/dist/providers/oauth/claude-code-credentials.js +133 -0
- package/dist/providers/oauth/claude-code-credentials.js.map +1 -0
- package/dist/providers/oauth/claude-code-login.d.ts +124 -0
- package/dist/providers/oauth/claude-code-login.d.ts.map +1 -0
- package/dist/providers/oauth/claude-code-login.js +230 -0
- package/dist/providers/oauth/claude-code-login.js.map +1 -0
- package/dist/providers/oauth/claude-code-oauth-client.d.ts +111 -0
- package/dist/providers/oauth/claude-code-oauth-client.d.ts.map +1 -0
- package/dist/providers/oauth/claude-code-oauth-client.js +207 -0
- package/dist/providers/oauth/claude-code-oauth-client.js.map +1 -0
- package/dist/providers/oauth/errors.d.ts +54 -0
- package/dist/providers/oauth/errors.d.ts.map +1 -0
- package/dist/providers/oauth/errors.js +79 -0
- package/dist/providers/oauth/errors.js.map +1 -0
- package/dist/providers/oauth/index.d.ts +105 -0
- package/dist/providers/oauth/index.d.ts.map +1 -0
- package/dist/providers/oauth/index.js +167 -0
- package/dist/providers/oauth/index.js.map +1 -0
- package/dist/providers/oauth/jwt-claims.d.ts +23 -0
- package/dist/providers/oauth/jwt-claims.d.ts.map +1 -0
- package/dist/providers/oauth/jwt-claims.js +67 -0
- package/dist/providers/oauth/jwt-claims.js.map +1 -0
- package/dist/providers/oauth/local-callback-server.d.ts +60 -0
- package/dist/providers/oauth/local-callback-server.d.ts.map +1 -0
- package/dist/providers/oauth/local-callback-server.js +148 -0
- package/dist/providers/oauth/local-callback-server.js.map +1 -0
- package/dist/providers/oauth/oauth-client.d.ts +55 -0
- package/dist/providers/oauth/oauth-client.d.ts.map +1 -0
- package/dist/providers/oauth/oauth-client.js +161 -0
- package/dist/providers/oauth/oauth-client.js.map +1 -0
- package/dist/providers/oauth/openai-oauth-provider.d.ts +129 -0
- package/dist/providers/oauth/openai-oauth-provider.d.ts.map +1 -0
- package/dist/providers/oauth/openai-oauth-provider.js +265 -0
- package/dist/providers/oauth/openai-oauth-provider.js.map +1 -0
- package/dist/providers/oauth/pkce-helper.d.ts +43 -0
- package/dist/providers/oauth/pkce-helper.d.ts.map +1 -0
- package/dist/providers/oauth/pkce-helper.js +57 -0
- package/dist/providers/oauth/pkce-helper.js.map +1 -0
- package/dist/providers/oauth/redaction.d.ts +22 -0
- package/dist/providers/oauth/redaction.d.ts.map +1 -0
- package/dist/providers/oauth/redaction.js +59 -0
- package/dist/providers/oauth/redaction.js.map +1 -0
- package/dist/providers/oauth/secure-credential-store.d.ts +67 -0
- package/dist/providers/oauth/secure-credential-store.d.ts.map +1 -0
- package/dist/providers/oauth/secure-credential-store.js +73 -0
- package/dist/providers/oauth/secure-credential-store.js.map +1 -0
- package/dist/providers/oauth/token-store.d.ts +53 -0
- package/dist/providers/oauth/token-store.d.ts.map +1 -0
- package/dist/providers/oauth/token-store.js +78 -0
- package/dist/providers/oauth/token-store.js.map +1 -0
- package/dist/providers/oauth/types.d.ts +64 -0
- package/dist/providers/oauth/types.d.ts.map +1 -0
- package/dist/providers/oauth/types.js +12 -0
- package/dist/providers/oauth/types.js.map +1 -0
- package/dist/providers/object-tracking.d.ts +47 -0
- package/dist/providers/object-tracking.d.ts.map +1 -0
- package/dist/providers/object-tracking.js +46 -0
- package/dist/providers/object-tracking.js.map +1 -0
- package/dist/providers/offline-model-index.d.ts +20 -0
- package/dist/providers/offline-model-index.d.ts.map +1 -0
- package/dist/providers/offline-model-index.js +112 -0
- package/dist/providers/offline-model-index.js.map +1 -0
- package/dist/providers/ollama-provider.d.ts +28 -1
- package/dist/providers/ollama-provider.d.ts.map +1 -1
- package/dist/providers/ollama-provider.js +193 -43
- package/dist/providers/ollama-provider.js.map +1 -1
- package/dist/providers/openai-compat/client.d.ts +57 -0
- package/dist/providers/openai-compat/client.d.ts.map +1 -0
- package/dist/providers/openai-compat/client.js +157 -0
- package/dist/providers/openai-compat/client.js.map +1 -0
- package/dist/providers/openai-compat/decode.d.ts +36 -0
- package/dist/providers/openai-compat/decode.d.ts.map +1 -0
- package/dist/providers/openai-compat/decode.js +55 -0
- package/dist/providers/openai-compat/decode.js.map +1 -0
- package/dist/providers/openai-compat/errors.d.ts +54 -0
- package/dist/providers/openai-compat/errors.d.ts.map +1 -0
- package/dist/providers/openai-compat/errors.js +144 -0
- package/dist/providers/openai-compat/errors.js.map +1 -0
- package/dist/providers/openai-compat/index.d.ts +8 -0
- package/dist/providers/openai-compat/index.d.ts.map +1 -0
- package/dist/providers/openai-compat/index.js +5 -0
- package/dist/providers/openai-compat/index.js.map +1 -0
- package/dist/providers/openai-compat/sse.d.ts +14 -0
- package/dist/providers/openai-compat/sse.d.ts.map +1 -0
- package/dist/providers/openai-compat/sse.js +69 -0
- package/dist/providers/openai-compat/sse.js.map +1 -0
- package/dist/providers/openai-compat/types.d.ts +75 -0
- package/dist/providers/openai-compat/types.d.ts.map +1 -0
- package/dist/providers/openai-compat/types.js +9 -0
- package/dist/providers/openai-compat/types.js.map +1 -0
- package/dist/providers/openai-compat-provider.d.ts +90 -0
- package/dist/providers/openai-compat-provider.d.ts.map +1 -0
- package/dist/providers/openai-compat-provider.js +282 -0
- package/dist/providers/openai-compat-provider.js.map +1 -0
- package/dist/providers/openai-provider.d.ts +89 -26
- package/dist/providers/openai-provider.d.ts.map +1 -1
- package/dist/providers/openai-provider.js +990 -105
- package/dist/providers/openai-provider.js.map +1 -1
- package/dist/providers/openrouter-provider.d.ts +6 -12
- package/dist/providers/openrouter-provider.d.ts.map +1 -1
- package/dist/providers/openrouter-provider.js +24 -53
- package/dist/providers/openrouter-provider.js.map +1 -1
- package/dist/providers/provider-call-failure.d.ts +39 -0
- package/dist/providers/provider-call-failure.d.ts.map +1 -0
- package/dist/providers/provider-call-failure.js +132 -0
- package/dist/providers/provider-call-failure.js.map +1 -0
- package/dist/providers/provider-error.d.ts +59 -0
- package/dist/providers/provider-error.d.ts.map +1 -0
- package/dist/providers/provider-error.js +165 -0
- package/dist/providers/provider-error.js.map +1 -0
- package/dist/providers/provider-generations.d.ts +99 -0
- package/dist/providers/provider-generations.d.ts.map +1 -0
- package/dist/providers/provider-generations.js +71 -0
- package/dist/providers/provider-generations.js.map +1 -0
- package/dist/providers/provider-queue.d.ts +62 -0
- package/dist/providers/provider-queue.d.ts.map +1 -0
- package/dist/providers/provider-queue.js +28 -0
- package/dist/providers/provider-queue.js.map +1 -0
- package/dist/providers/provider-registry.d.ts +33 -14
- package/dist/providers/provider-registry.d.ts.map +1 -1
- package/dist/providers/provider-registry.js +85 -68
- package/dist/providers/provider-registry.js.map +1 -1
- package/dist/providers/provider-request-log.d.ts +53 -0
- package/dist/providers/provider-request-log.d.ts.map +1 -0
- package/dist/providers/provider-request-log.js +157 -0
- package/dist/providers/provider-request-log.js.map +1 -0
- package/dist/providers/provider-session.d.ts +3 -0
- package/dist/providers/provider-session.d.ts.map +1 -0
- package/dist/providers/provider-session.js +10 -0
- package/dist/providers/provider-session.js.map +1 -0
- package/dist/providers/provider-transport.d.ts +11 -0
- package/dist/providers/provider-transport.d.ts.map +1 -0
- package/dist/providers/provider-transport.js +11 -0
- package/dist/providers/provider-transport.js.map +1 -0
- package/dist/providers/python-provider.d.ts +20 -12
- package/dist/providers/python-provider.d.ts.map +1 -1
- package/dist/providers/python-provider.js +185 -25
- package/dist/providers/python-provider.js.map +1 -1
- package/dist/providers/replicate-provider.d.ts +89 -7
- package/dist/providers/replicate-provider.d.ts.map +1 -1
- package/dist/providers/replicate-provider.js +801 -65
- package/dist/providers/replicate-provider.js.map +1 -1
- package/dist/providers/replicate-retry.d.ts +30 -0
- package/dist/providers/replicate-retry.d.ts.map +1 -0
- package/dist/providers/replicate-retry.js +97 -0
- package/dist/providers/replicate-retry.js.map +1 -0
- package/dist/providers/responses-api.d.ts +27 -0
- package/dist/providers/responses-api.d.ts.map +1 -0
- package/dist/providers/responses-api.js +297 -0
- package/dist/providers/responses-api.js.map +1 -0
- package/dist/providers/reve-provider.d.ts +45 -0
- package/dist/providers/reve-provider.d.ts.map +1 -0
- package/dist/providers/reve-provider.js +159 -0
- package/dist/providers/reve-provider.js.map +1 -0
- package/dist/providers/rodin-provider.d.ts +23 -1
- package/dist/providers/rodin-provider.d.ts.map +1 -1
- package/dist/providers/rodin-provider.js +89 -51
- package/dist/providers/rodin-provider.js.map +1 -1
- package/dist/providers/safe-url.d.ts +70 -0
- package/dist/providers/safe-url.d.ts.map +1 -0
- package/dist/providers/safe-url.js +277 -0
- package/dist/providers/safe-url.js.map +1 -0
- package/dist/providers/scripted-provider.d.ts +9 -0
- package/dist/providers/scripted-provider.d.ts.map +1 -1
- package/dist/providers/scripted-provider.js +86 -10
- package/dist/providers/scripted-provider.js.map +1 -1
- package/dist/providers/structured-output.d.ts +42 -0
- package/dist/providers/structured-output.d.ts.map +1 -0
- package/dist/providers/structured-output.js +83 -0
- package/dist/providers/structured-output.js.map +1 -0
- package/dist/providers/together-provider.d.ts +19 -16
- package/dist/providers/together-provider.d.ts.map +1 -1
- package/dist/providers/together-provider.js +103 -225
- package/dist/providers/together-provider.js.map +1 -1
- package/dist/providers/topaz-provider.d.ts +44 -0
- package/dist/providers/topaz-provider.d.ts.map +1 -0
- package/dist/providers/topaz-provider.js +239 -0
- package/dist/providers/topaz-provider.js.map +1 -0
- package/dist/providers/types.d.ts +603 -4
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js +81 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/providers/useapi-provider.d.ts +27 -0
- package/dist/providers/useapi-provider.d.ts.map +1 -0
- package/dist/providers/useapi-provider.js +266 -0
- package/dist/providers/useapi-provider.js.map +1 -0
- package/dist/providers/video-duration.d.ts +6 -0
- package/dist/providers/video-duration.d.ts.map +1 -0
- package/dist/providers/video-duration.js +63 -0
- package/dist/providers/video-duration.js.map +1 -0
- package/dist/providers/video-frame-fallback.d.ts +39 -0
- package/dist/providers/video-frame-fallback.d.ts.map +1 -0
- package/dist/providers/video-frame-fallback.js +155 -0
- package/dist/providers/video-frame-fallback.js.map +1 -0
- package/dist/providers/video-frames.d.ts +61 -0
- package/dist/providers/video-frames.d.ts.map +1 -0
- package/dist/providers/video-frames.js +208 -0
- package/dist/providers/video-frames.js.map +1 -0
- package/dist/providers/video-mime.d.ts +14 -0
- package/dist/providers/video-mime.d.ts.map +1 -0
- package/dist/providers/video-mime.js +44 -0
- package/dist/providers/video-mime.js.map +1 -0
- package/dist/providers/video-to-audio.d.ts +34 -0
- package/dist/providers/video-to-audio.d.ts.map +1 -0
- package/dist/providers/video-to-audio.js +62 -0
- package/dist/providers/video-to-audio.js.map +1 -0
- package/dist/providers/vllm-provider.d.ts +22 -8
- package/dist/providers/vllm-provider.d.ts.map +1 -1
- package/dist/providers/vllm-provider.js +48 -23
- package/dist/providers/vllm-provider.js.map +1 -1
- package/dist/providers/voyage-provider.d.ts +10 -2
- package/dist/providers/voyage-provider.d.ts.map +1 -1
- package/dist/providers/voyage-provider.js +16 -7
- package/dist/providers/voyage-provider.js.map +1 -1
- package/dist/providers/xai-provider.d.ts +54 -13
- package/dist/providers/xai-provider.d.ts.map +1 -1
- package/dist/providers/xai-provider.js +299 -22
- package/dist/providers/xai-provider.js.map +1 -1
- package/dist/python-bridge-base.d.ts +358 -0
- package/dist/python-bridge-base.d.ts.map +1 -0
- package/dist/python-bridge-base.js +1557 -0
- package/dist/python-bridge-base.js.map +1 -0
- package/dist/python-bridge-codec.d.ts +28 -0
- package/dist/python-bridge-codec.d.ts.map +1 -0
- package/dist/python-bridge-codec.js +39 -0
- package/dist/python-bridge-codec.js.map +1 -0
- package/dist/python-bridge-factory.d.ts +52 -0
- package/dist/python-bridge-factory.d.ts.map +1 -0
- package/dist/python-bridge-factory.js +69 -0
- package/dist/python-bridge-factory.js.map +1 -0
- package/dist/python-bridge-framing.d.ts +68 -0
- package/dist/python-bridge-framing.d.ts.map +1 -0
- package/dist/python-bridge-framing.js +91 -0
- package/dist/python-bridge-framing.js.map +1 -0
- package/dist/python-bridge-types.d.ts +545 -2
- package/dist/python-bridge-types.d.ts.map +1 -1
- package/dist/python-bridge-types.js +49 -1
- package/dist/python-bridge-types.js.map +1 -1
- package/dist/python-graph-resolver.d.ts +57 -0
- package/dist/python-graph-resolver.d.ts.map +1 -0
- package/dist/python-graph-resolver.js +79 -0
- package/dist/python-graph-resolver.js.map +1 -0
- package/dist/python-node-executor.d.ts +36 -4
- package/dist/python-node-executor.d.ts.map +1 -1
- package/dist/python-node-executor.js +177 -86
- package/dist/python-node-executor.js.map +1 -1
- package/dist/python-stdio-bridge.d.ts +18 -37
- package/dist/python-stdio-bridge.d.ts.map +1 -1
- package/dist/python-stdio-bridge.js +148 -475
- package/dist/python-stdio-bridge.js.map +1 -1
- package/dist/python-websocket-bridge.d.ts +140 -0
- package/dist/python-websocket-bridge.d.ts.map +1 -0
- package/dist/python-websocket-bridge.js +561 -0
- package/dist/python-websocket-bridge.js.map +1 -0
- package/dist/python-worker-stderr.d.ts +4 -0
- package/dist/python-worker-stderr.d.ts.map +1 -0
- package/dist/python-worker-stderr.js +24 -0
- package/dist/python-worker-stderr.js.map +1 -0
- package/dist/recommended-models.d.ts +2 -2
- package/dist/recommended-models.d.ts.map +1 -1
- package/dist/recommended-models.js +24 -4
- package/dist/recommended-models.js.map +1 -1
- package/dist/recoverable-node-error.d.ts +31 -0
- package/dist/recoverable-node-error.d.ts.map +1 -0
- package/dist/recoverable-node-error.js +37 -0
- package/dist/recoverable-node-error.js.map +1 -0
- package/dist/redact-params.d.ts +13 -0
- package/dist/redact-params.d.ts.map +1 -0
- package/dist/redact-params.js +57 -0
- package/dist/redact-params.js.map +1 -0
- package/dist/sandbox-module-catalog.d.ts +43 -0
- package/dist/sandbox-module-catalog.d.ts.map +1 -0
- package/dist/sandbox-module-catalog.js +25 -0
- package/dist/sandbox-module-catalog.js.map +1 -0
- package/dist/storage-workspace.d.ts +59 -0
- package/dist/storage-workspace.d.ts.map +1 -0
- package/dist/storage-workspace.js +426 -0
- package/dist/storage-workspace.js.map +1 -0
- package/dist/swappable-python-bridge.d.ts +83 -0
- package/dist/swappable-python-bridge.d.ts.map +1 -0
- package/dist/swappable-python-bridge.js +246 -0
- package/dist/swappable-python-bridge.js.map +1 -0
- package/dist/telemetry.d.ts +7 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +23 -0
- package/dist/telemetry.js.map +1 -1
- package/dist/testing.d.ts +81 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +130 -0
- package/dist/testing.js.map +1 -0
- package/dist/token-counter.d.ts +30 -0
- package/dist/token-counter.d.ts.map +1 -0
- package/dist/token-counter.js +156 -0
- package/dist/token-counter.js.map +1 -0
- package/dist/trace-exporters.d.ts +10 -0
- package/dist/trace-exporters.d.ts.map +1 -1
- package/dist/trace-exporters.js +59 -20
- package/dist/trace-exporters.js.map +1 -1
- package/dist/tracing-helpers.d.ts +45 -4
- package/dist/tracing-helpers.d.ts.map +1 -1
- package/dist/tracing-helpers.js +62 -19
- package/dist/tracing-helpers.js.map +1 -1
- package/dist/turn-budget.d.ts +278 -0
- package/dist/turn-budget.d.ts.map +1 -0
- package/dist/turn-budget.js +365 -0
- package/dist/turn-budget.js.map +1 -0
- package/dist/variable-channel.d.ts +48 -0
- package/dist/variable-channel.d.ts.map +1 -0
- package/dist/variable-channel.js +110 -0
- package/dist/variable-channel.js.map +1 -0
- package/dist/workspace.d.ts +119 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +112 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +107 -19
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a video with a vision model that has no video content part.
|
|
3
|
+
*
|
|
4
|
+
* Most chat APIs are OpenAI-compatible and have nowhere to put a clip, so a
|
|
5
|
+
* `video` part reaching them used to be a hard refusal — even when the model
|
|
6
|
+
* behind the endpoint reads images perfectly well. This samples the clip into
|
|
7
|
+
* stills with ffmpeg and puts them on the message as ordinary image parts,
|
|
8
|
+
* labelled with their timestamps so the model can reason about order and
|
|
9
|
+
* timing.
|
|
10
|
+
*
|
|
11
|
+
* It is a downgrade, and it says so: the header text names the frame count and
|
|
12
|
+
* the sample rate, so a model that needs continuous motion or the audio track
|
|
13
|
+
* can report that it is missing rather than inventing it. A provider that
|
|
14
|
+
* reads video natively (`supportsVideoInput`) never comes through here.
|
|
15
|
+
*/
|
|
16
|
+
import { safeFetch } from "./safe-url.js";
|
|
17
|
+
import { sampleVideoFrames } from "./video-frames.js";
|
|
18
|
+
import { createLogger } from "@nodetool-ai/config";
|
|
19
|
+
const log = createLogger("nodetool:video-frame-fallback");
|
|
20
|
+
/**
|
|
21
|
+
* Whether the fallback is on. `NODETOOL_VIDEO_FRAME_FALLBACK=0` turns it off
|
|
22
|
+
* and restores the old refusal, for a caller that would rather fail than
|
|
23
|
+
* silently pay for a lossy read.
|
|
24
|
+
*/
|
|
25
|
+
export function videoFrameFallbackEnabled() {
|
|
26
|
+
const raw = globalThis.process?.env?.["NODETOOL_VIDEO_FRAME_FALLBACK"];
|
|
27
|
+
return raw !== "0" && raw !== "false";
|
|
28
|
+
}
|
|
29
|
+
/** Whether any message carries a `video` content part. */
|
|
30
|
+
function messagesContainVideo(messages) {
|
|
31
|
+
return messages.some((m) => Array.isArray(m.content) && m.content.some((c) => c.type === "video"));
|
|
32
|
+
}
|
|
33
|
+
function decodeBase64(b64) {
|
|
34
|
+
return new Uint8Array(Buffer.from(b64, "base64"));
|
|
35
|
+
}
|
|
36
|
+
/** The bytes behind a `data:` URI. */
|
|
37
|
+
function parseDataUri(uri) {
|
|
38
|
+
const comma = uri.indexOf(",");
|
|
39
|
+
if (comma < 0)
|
|
40
|
+
throw new Error("Invalid data URI");
|
|
41
|
+
return decodeBase64(uri.slice(comma + 1));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Source a video part's bytes: inline data first, then its URI. The container
|
|
45
|
+
* type is not read off the ref — ffmpeg sniffs it from the file itself, which
|
|
46
|
+
* is right more often than a `mimeType` the caller guessed.
|
|
47
|
+
*/
|
|
48
|
+
async function videoContentBytes(video, options) {
|
|
49
|
+
if (typeof video.data === "string" && video.data.length > 0) {
|
|
50
|
+
return video.data.startsWith("data:")
|
|
51
|
+
? parseDataUri(video.data)
|
|
52
|
+
: decodeBase64(video.data);
|
|
53
|
+
}
|
|
54
|
+
if (video.data instanceof Uint8Array && video.data.length > 0) {
|
|
55
|
+
return video.data;
|
|
56
|
+
}
|
|
57
|
+
if (!video.uri)
|
|
58
|
+
return new Uint8Array();
|
|
59
|
+
const resolved = video.uri.startsWith("data:")
|
|
60
|
+
? video.uri
|
|
61
|
+
: ((await options.resolveUri?.(video.uri)) ?? video.uri);
|
|
62
|
+
if (resolved.startsWith("data:"))
|
|
63
|
+
return parseDataUri(resolved);
|
|
64
|
+
const resp = await safeFetch(resolved, options.signal ? { signal: options.signal } : undefined);
|
|
65
|
+
if (!resp.ok)
|
|
66
|
+
throw new Error(`Failed to fetch video: ${resp.status}`);
|
|
67
|
+
return new Uint8Array(await resp.arrayBuffer());
|
|
68
|
+
}
|
|
69
|
+
function round(value, digits = 1) {
|
|
70
|
+
return value.toFixed(digits).replace(/\.0+$/, "");
|
|
71
|
+
}
|
|
72
|
+
/** The header that tells the model what it is looking at, and what it is not. */
|
|
73
|
+
export function frameHeaderText(sample) {
|
|
74
|
+
const count = sample.frames.length;
|
|
75
|
+
const duration = sample.durationSec !== null ? `${round(sample.durationSec)}s ` : "";
|
|
76
|
+
const rate = sample.fps >= 1
|
|
77
|
+
? `${round(sample.fps, 2)} frames/second`
|
|
78
|
+
: `one frame every ${round(1 / sample.fps, 1)}s`;
|
|
79
|
+
const cut = sample.truncated
|
|
80
|
+
? ` Sampling stopped at the frame limit, so the end of the clip is not shown.`
|
|
81
|
+
: "";
|
|
82
|
+
return (`[The following ${count} still frame${count === 1 ? "" : "s"} were ` +
|
|
83
|
+
`sampled from a ${duration}video at ${rate}, in order. They are stills: ` +
|
|
84
|
+
`there is no audio and no motion between them.${cut}]`);
|
|
85
|
+
}
|
|
86
|
+
/** One frame as an image part, preceded by its timestamp. */
|
|
87
|
+
function framePartsFor(sample) {
|
|
88
|
+
const parts = [];
|
|
89
|
+
for (const [index, frame] of sample.frames.entries()) {
|
|
90
|
+
parts.push({
|
|
91
|
+
type: "text",
|
|
92
|
+
text: `Frame ${index + 1} at ${round(frame.timeSec)}s:`
|
|
93
|
+
});
|
|
94
|
+
parts.push({
|
|
95
|
+
type: "image_url",
|
|
96
|
+
image: {
|
|
97
|
+
uri: `data:${frame.mimeType};base64,${Buffer.from(frame.data).toString("base64")}`,
|
|
98
|
+
mimeType: frame.mimeType
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return parts;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Replace every `video` content part with sampled frames. Messages with no
|
|
106
|
+
* video are returned untouched (same object identity), so this is cheap to
|
|
107
|
+
* call on every request.
|
|
108
|
+
*/
|
|
109
|
+
export async function expandVideoContentAsFrames(messages, options = {}) {
|
|
110
|
+
if (!messagesContainVideo(messages))
|
|
111
|
+
return messages;
|
|
112
|
+
const out = [];
|
|
113
|
+
for (const message of messages) {
|
|
114
|
+
if (!Array.isArray(message.content) ||
|
|
115
|
+
!message.content.some((c) => c.type === "video")) {
|
|
116
|
+
out.push(message);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const parts = [];
|
|
120
|
+
for (const part of message.content) {
|
|
121
|
+
if (part.type !== "video") {
|
|
122
|
+
parts.push(part);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const bytes = await videoContentBytes(part.video, options);
|
|
126
|
+
if (bytes.length === 0) {
|
|
127
|
+
parts.push({
|
|
128
|
+
type: "text",
|
|
129
|
+
text: "[A video was attached but its bytes could not be read.]"
|
|
130
|
+
});
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const sample = await sampleVideoFrames(bytes, {
|
|
134
|
+
signal: options.signal
|
|
135
|
+
});
|
|
136
|
+
if (sample.frames.length === 0) {
|
|
137
|
+
throw new Error(`ffmpeg decoded no frames from the attached video, so ` +
|
|
138
|
+
`${options.provider ?? "this provider"} has nothing to read. The ` +
|
|
139
|
+
`file may not be a video, or may use a codec this ffmpeg build ` +
|
|
140
|
+
`does not decode.`);
|
|
141
|
+
}
|
|
142
|
+
log.debug("Sampled a video into frames", {
|
|
143
|
+
provider: options.provider,
|
|
144
|
+
frames: sample.frames.length,
|
|
145
|
+
fps: sample.fps,
|
|
146
|
+
durationSec: sample.durationSec
|
|
147
|
+
});
|
|
148
|
+
parts.push({ type: "text", text: frameHeaderText(sample) });
|
|
149
|
+
parts.push(...framePartsFor(sample));
|
|
150
|
+
}
|
|
151
|
+
out.push({ ...message, content: parts });
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=video-frame-fallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-frame-fallback.js","sourceRoot":"","sources":["../../src/providers/video-frame-fallback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAyB,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,GAAG,GAAG,YAAY,CAAC,+BAA+B,CAAC,CAAC;AAU1D;;;;GAIG;AACH,MAAM,UAAU,yBAAyB;IACvC,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,+BAA+B,CAAC,CAAC;IACvE,OAAO,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,OAAO,CAAC;AACxC,CAAC;AAED,0DAA0D;AAC1D,SAAS,oBAAoB,CAAC,QAA4B;IACxD,OAAO,QAAQ,CAAC,IAAI,CAClB,CAAC,CAAC,EAAE,EAAE,CACJ,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CACxE,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,sCAAsC;AACtC,SAAS,YAAY,CAAC,GAAW;IAC/B,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACnD,OAAO,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,iBAAiB,CAC9B,KAAmC,EACnC,OAAkC;IAElC,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5D,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YACnC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC;YAC1B,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,YAAY,UAAU,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9D,OAAO,KAAK,CAAC,IAAI,CAAC;IACpB,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,GAAG;QAAE,OAAO,IAAI,UAAU,EAAE,CAAC;IAExC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC;QAC5C,CAAC,CAAC,KAAK,CAAC,GAAG;QACX,CAAC,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3D,IAAI,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;IAEhE,MAAM,IAAI,GAAG,MAAM,SAAS,CAC1B,QAAQ,EACR,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CACxD,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,OAAO,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,KAAK,CAAC,KAAa,EAAE,MAAM,GAAG,CAAC;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,eAAe,CAAC,MAAwB;IACtD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;IACnC,MAAM,QAAQ,GACZ,MAAM,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,MAAM,IAAI,GACR,MAAM,CAAC,GAAG,IAAI,CAAC;QACb,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,gBAAgB;QACzC,CAAC,CAAC,mBAAmB,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IACrD,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS;QAC1B,CAAC,CAAC,4EAA4E;QAC9E,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,CACL,kBAAkB,KAAK,eAAe,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,QAAQ;QACpE,kBAAkB,QAAQ,YAAY,IAAI,+BAA+B;QACzE,gDAAgD,GAAG,GAAG,CACvD,CAAC;AACJ,CAAC;AAED,6DAA6D;AAC7D,SAAS,aAAa,CAAC,MAAwB;IAC7C,MAAM,KAAK,GAAqB,EAAE,CAAC;IACnC,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACrD,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,SAAS,KAAK,GAAG,CAAC,OAAO,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI;SACxD,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,WAAW;YACjB,KAAK,EAAE;gBACL,GAAG,EAAE,QAAQ,KAAK,CAAC,QAAQ,WAAW,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;gBAClF,QAAQ,EAAE,KAAK,CAAC,QAAQ;aACzB;SACF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,QAAmB,EACnB,OAAO,GAA8B,EAAE;IAEvC,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAErD,MAAM,GAAG,GAAc,EAAE,CAAC;IAC1B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IACE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;YAC/B,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,EAChD,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClB,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAqB,EAAE,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACjB,SAAS;YACX,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAClC,IAA4B,CAAC,KAAK,EACnC,OAAO,CACR,CAAC;YACF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,yDAAyD;iBAChE,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,KAAK,EAAE;gBAC5C,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAC,CAAC;YACH,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CACb,uDAAuD;oBACrD,GAAG,OAAO,CAAC,QAAQ,IAAI,eAAe,4BAA4B;oBAClE,gEAAgE;oBAChE,kBAAkB,CACrB,CAAC;YACJ,CAAC;YACD,GAAG,CAAC,KAAK,CAAC,6BAA6B,EAAE;gBACvC,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM;gBAC5B,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,WAAW,EAAE,MAAM,CAAC,WAAW;aAChC,CAAC,CAAC;YACH,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC5D,KAAK,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;QACvC,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sample a video into still frames with ffmpeg.
|
|
3
|
+
*
|
|
4
|
+
* This is what lets a vision model that cannot read a clip still answer
|
|
5
|
+
* questions about one: the bytes are decoded here, a bounded number of frames
|
|
6
|
+
* come back as JPEGs, and the caller sends them as ordinary image content.
|
|
7
|
+
*
|
|
8
|
+
* The argv is ours, not a model's — the only input path is a temp file this
|
|
9
|
+
* module wrote — so the containment `packages/agents/src/host-binary-guard.ts`
|
|
10
|
+
* applies to a model-supplied argv is not needed. `-protocol_whitelist file`
|
|
11
|
+
* and `-nostdin` still go in: an mp4 can name an external opener, and a child
|
|
12
|
+
* that inherits the server's stdin outlives the call.
|
|
13
|
+
*/
|
|
14
|
+
/** A single sampled frame, JPEG-encoded. */
|
|
15
|
+
export type SampledFrame = {
|
|
16
|
+
data: Uint8Array;
|
|
17
|
+
mimeType: string;
|
|
18
|
+
/** Seconds into the clip, derived from the sample rate. */
|
|
19
|
+
timeSec: number;
|
|
20
|
+
};
|
|
21
|
+
export type VideoFrameSample = {
|
|
22
|
+
frames: SampledFrame[];
|
|
23
|
+
/** Clip length from ffprobe, or null when the probe did not answer. */
|
|
24
|
+
durationSec: number | null;
|
|
25
|
+
/** Frames per second actually requested of ffmpeg. */
|
|
26
|
+
fps: number;
|
|
27
|
+
/**
|
|
28
|
+
* True when the frame cap stopped the sample before the end of the clip.
|
|
29
|
+
* Only reachable with an unknown duration: once ffprobe answers, the rate is
|
|
30
|
+
* chosen to fit the budget across the whole clip and the cap never bites.
|
|
31
|
+
*/
|
|
32
|
+
truncated: boolean;
|
|
33
|
+
};
|
|
34
|
+
export type SampleVideoFramesOptions = {
|
|
35
|
+
/** Hard cap on frames returned. */
|
|
36
|
+
maxFrames?: number;
|
|
37
|
+
/** Ceiling on the sample rate; a short clip is sampled no denser than this. */
|
|
38
|
+
maxFps?: number;
|
|
39
|
+
/** Longest edge of each frame, in pixels. Frames are never upscaled. */
|
|
40
|
+
maxDimension?: number;
|
|
41
|
+
signal?: AbortSignal;
|
|
42
|
+
};
|
|
43
|
+
/** ffmpeg or ffprobe is not installed. Names the binary and the way out. */
|
|
44
|
+
export declare class FrameSamplingUnavailableError extends Error {
|
|
45
|
+
readonly binary: string;
|
|
46
|
+
constructor(binary: string);
|
|
47
|
+
}
|
|
48
|
+
/** Read a video duration from its bytes without decoding frames. */
|
|
49
|
+
export declare function probeVideoDurationSeconds(bytes: Uint8Array, signal: AbortSignal): Promise<number | null>;
|
|
50
|
+
/**
|
|
51
|
+
* The sample rate that spreads `maxFrames` across the whole clip without
|
|
52
|
+
* exceeding `maxFps`. An unknown duration samples at the ceiling and lets the
|
|
53
|
+
* frame cap stop it.
|
|
54
|
+
*/
|
|
55
|
+
export declare function frameRateFor(durationSec: number | null, maxFrames: number, maxFps: number): number;
|
|
56
|
+
/**
|
|
57
|
+
* Decode `bytes` and return up to `maxFrames` JPEG stills spread across the
|
|
58
|
+
* clip. Throws {@link FrameSamplingUnavailableError} when ffmpeg is absent.
|
|
59
|
+
*/
|
|
60
|
+
export declare function sampleVideoFrames(bytes: Uint8Array, options?: SampleVideoFramesOptions): Promise<VideoFrameSample>;
|
|
61
|
+
//# sourceMappingURL=video-frames.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-frames.d.ts","sourceRoot":"","sources":["../../src/providers/video-frames.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,4CAA4C;AAC5C,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,uEAAuE;IACvE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,4EAA4E;AAC5E,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,YAAY,MAAM,EAAE,MAAM,EASzB;CACF;AAwHD,oEAAoE;AACpE,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuBxB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,MAAM,CAMR;AAYD;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,gBAAgB,CAAC,CA4D3B"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sample a video into still frames with ffmpeg.
|
|
3
|
+
*
|
|
4
|
+
* This is what lets a vision model that cannot read a clip still answer
|
|
5
|
+
* questions about one: the bytes are decoded here, a bounded number of frames
|
|
6
|
+
* come back as JPEGs, and the caller sends them as ordinary image content.
|
|
7
|
+
*
|
|
8
|
+
* The argv is ours, not a model's — the only input path is a temp file this
|
|
9
|
+
* module wrote — so the containment `packages/agents/src/host-binary-guard.ts`
|
|
10
|
+
* applies to a model-supplied argv is not needed. `-protocol_whitelist file`
|
|
11
|
+
* and `-nostdin` still go in: an mp4 can name an external opener, and a child
|
|
12
|
+
* that inherits the server's stdin outlives the call.
|
|
13
|
+
*/
|
|
14
|
+
import { importNodeBuiltin } from "@nodetool-ai/config";
|
|
15
|
+
import { withSpan } from "../tracing-helpers.js";
|
|
16
|
+
import { mp4DurationSeconds } from "./video-duration.js";
|
|
17
|
+
/** ffmpeg or ffprobe is not installed. Names the binary and the way out. */
|
|
18
|
+
export class FrameSamplingUnavailableError extends Error {
|
|
19
|
+
binary;
|
|
20
|
+
constructor(binary) {
|
|
21
|
+
super(`${binary} is not installed or not on PATH. Reading a video with a ` +
|
|
22
|
+
`provider that has no video content part samples frames with ffmpeg ` +
|
|
23
|
+
`first — install ffmpeg (the Package Manager UI can do this), or use ` +
|
|
24
|
+
`a provider whose chat models read video natively (gemini).`);
|
|
25
|
+
this.name = "FrameSamplingUnavailableError";
|
|
26
|
+
this.binary = binary;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const DEFAULT_MAX_FRAMES = 16;
|
|
30
|
+
const DEFAULT_MAX_FPS = 1;
|
|
31
|
+
const DEFAULT_MAX_DIMENSION = 768;
|
|
32
|
+
/** ffmpeg `-q:v` for the JPEG encoder (2 = best, 31 = worst). */
|
|
33
|
+
const JPEG_QUALITY = 4;
|
|
34
|
+
const FFMPEG_MAX_BUFFER = 8 * 1024 * 1024;
|
|
35
|
+
/** Read a positive number from the environment, or fall back. */
|
|
36
|
+
function envNumber(name, fallback) {
|
|
37
|
+
const raw = Number(globalThis.process?.env?.[name]);
|
|
38
|
+
return Number.isFinite(raw) && raw > 0 ? raw : fallback;
|
|
39
|
+
}
|
|
40
|
+
/** Frame-sampling limits, env-overridable. Read per call so a test can vary them. */
|
|
41
|
+
function frameSamplingLimits() {
|
|
42
|
+
return {
|
|
43
|
+
maxFrames: Math.floor(envNumber("NODETOOL_VIDEO_FRAME_MAX_FRAMES", DEFAULT_MAX_FRAMES)),
|
|
44
|
+
maxFps: envNumber("NODETOOL_VIDEO_FRAME_MAX_FPS", DEFAULT_MAX_FPS),
|
|
45
|
+
maxDimension: Math.floor(envNumber("NODETOOL_VIDEO_FRAME_MAX_DIMENSION", DEFAULT_MAX_DIMENSION))
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async function nodeModules() {
|
|
49
|
+
const [cp, fs, os, path] = await Promise.all([
|
|
50
|
+
importNodeBuiltin("node:child_process"),
|
|
51
|
+
importNodeBuiltin("node:fs/promises"),
|
|
52
|
+
importNodeBuiltin("node:os"),
|
|
53
|
+
importNodeBuiltin("node:path")
|
|
54
|
+
]);
|
|
55
|
+
if (!cp || !fs || !os || !path) {
|
|
56
|
+
throw new Error("Video frame sampling requires Node built-in modules");
|
|
57
|
+
}
|
|
58
|
+
return { cp, fs, os, path };
|
|
59
|
+
}
|
|
60
|
+
/** Whether a spawn failed because the binary is not on PATH. */
|
|
61
|
+
function isSpawnEnoent(err) {
|
|
62
|
+
return (typeof err === "object" &&
|
|
63
|
+
err !== null &&
|
|
64
|
+
err.code === "ENOENT");
|
|
65
|
+
}
|
|
66
|
+
async function run(cp, binary, args, signal) {
|
|
67
|
+
return await new Promise((resolve, reject) => {
|
|
68
|
+
cp.execFile(binary, args, { maxBuffer: FFMPEG_MAX_BUFFER, signal, windowsHide: true }, (error, stdout, stderr) => {
|
|
69
|
+
if (error) {
|
|
70
|
+
if (isSpawnEnoent(error)) {
|
|
71
|
+
reject(new FrameSamplingUnavailableError(binary));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
reject(error);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
resolve({ stdout: String(stdout), stderr: String(stderr) });
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/** Clip length in seconds, or null when ffprobe cannot say. */
|
|
82
|
+
async function probeDuration(cp, file, signal) {
|
|
83
|
+
try {
|
|
84
|
+
const { stdout } = await run(cp, "ffprobe", [
|
|
85
|
+
"-v",
|
|
86
|
+
"error",
|
|
87
|
+
"-show_entries",
|
|
88
|
+
"format=duration",
|
|
89
|
+
"-of",
|
|
90
|
+
"csv=p=0",
|
|
91
|
+
file
|
|
92
|
+
], signal);
|
|
93
|
+
const seconds = Number(stdout.trim().split("\n")[0]);
|
|
94
|
+
return Number.isFinite(seconds) && seconds > 0 ? seconds : null;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
if (signal?.aborted)
|
|
98
|
+
throw error;
|
|
99
|
+
// A missing binary is actionable and must reach the caller. A probe that
|
|
100
|
+
// ran and failed (an odd container, no format header) is not: the sample
|
|
101
|
+
// falls back to the ceiling rate below.
|
|
102
|
+
if (error instanceof FrameSamplingUnavailableError)
|
|
103
|
+
throw error;
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Read a video duration from its bytes without decoding frames. */
|
|
108
|
+
export async function probeVideoDurationSeconds(bytes, signal) {
|
|
109
|
+
signal.throwIfAborted();
|
|
110
|
+
const mp4Duration = mp4DurationSeconds(bytes);
|
|
111
|
+
if (mp4Duration !== null) {
|
|
112
|
+
signal.throwIfAborted();
|
|
113
|
+
return mp4Duration;
|
|
114
|
+
}
|
|
115
|
+
return withSpan("media.probe_video_duration", { "media.byte_length": bytes.byteLength }, async () => {
|
|
116
|
+
const { cp, fs, os, path } = await nodeModules();
|
|
117
|
+
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "nodetool-vduration-"));
|
|
118
|
+
const input = path.join(dir, "input.bin");
|
|
119
|
+
try {
|
|
120
|
+
await fs.writeFile(input, bytes, { signal });
|
|
121
|
+
return await probeDuration(cp, input, signal);
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
// Cleanup failure must not replace the duration result or probe error.
|
|
125
|
+
await fs.rm(dir, { recursive: true, force: true }).catch(() => { });
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The sample rate that spreads `maxFrames` across the whole clip without
|
|
131
|
+
* exceeding `maxFps`. An unknown duration samples at the ceiling and lets the
|
|
132
|
+
* frame cap stop it.
|
|
133
|
+
*/
|
|
134
|
+
export function frameRateFor(durationSec, maxFrames, maxFps) {
|
|
135
|
+
if (durationSec === null || durationSec <= 0)
|
|
136
|
+
return maxFps;
|
|
137
|
+
// The first frame lands at t=0, so N frames need N-1 intervals to reach the
|
|
138
|
+
// end of the clip. Sampling at N/duration instead leaves the tail unseen.
|
|
139
|
+
const spread = maxFrames > 1 ? (maxFrames - 1) / durationSec : 1 / durationSec;
|
|
140
|
+
return Math.min(maxFps, Math.max(spread, 0.01));
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Fit inside a square of `maxDimension` without upscaling. ffmpeg's
|
|
144
|
+
* `force_original_aspect_ratio=decrease` would enlarge a smaller frame, which
|
|
145
|
+
* costs tokens and adds no detail.
|
|
146
|
+
*/
|
|
147
|
+
function scaleFilter(maxDimension) {
|
|
148
|
+
const m = maxDimension;
|
|
149
|
+
return `scale='if(gt(iw,ih),min(${m},iw),-2)':'if(gt(iw,ih),-2,min(${m},ih))'`;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Decode `bytes` and return up to `maxFrames` JPEG stills spread across the
|
|
153
|
+
* clip. Throws {@link FrameSamplingUnavailableError} when ffmpeg is absent.
|
|
154
|
+
*/
|
|
155
|
+
export async function sampleVideoFrames(bytes, options = {}) {
|
|
156
|
+
const limits = frameSamplingLimits();
|
|
157
|
+
const maxFrames = Math.max(1, options.maxFrames ?? limits.maxFrames);
|
|
158
|
+
const maxFps = options.maxFps ?? limits.maxFps;
|
|
159
|
+
const maxDimension = options.maxDimension ?? limits.maxDimension;
|
|
160
|
+
const { cp, fs, os, path } = await nodeModules();
|
|
161
|
+
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "nodetool-vframes-"));
|
|
162
|
+
const input = path.join(dir, "input.bin");
|
|
163
|
+
const outDir = path.join(dir, "frames");
|
|
164
|
+
try {
|
|
165
|
+
await fs.writeFile(input, bytes);
|
|
166
|
+
await fs.mkdir(outDir);
|
|
167
|
+
const durationSec = await probeDuration(cp, input, options.signal);
|
|
168
|
+
const fps = frameRateFor(durationSec, maxFrames, maxFps);
|
|
169
|
+
await run(cp, "ffmpeg", [
|
|
170
|
+
"-nostdin",
|
|
171
|
+
"-y",
|
|
172
|
+
"-v",
|
|
173
|
+
"error",
|
|
174
|
+
"-protocol_whitelist",
|
|
175
|
+
"file",
|
|
176
|
+
"-i",
|
|
177
|
+
input,
|
|
178
|
+
"-vf",
|
|
179
|
+
`fps=${fps.toFixed(6)},${scaleFilter(maxDimension)}`,
|
|
180
|
+
"-frames:v",
|
|
181
|
+
String(maxFrames),
|
|
182
|
+
"-q:v",
|
|
183
|
+
String(JPEG_QUALITY),
|
|
184
|
+
path.join(outDir, "frame_%04d.jpg")
|
|
185
|
+
], options.signal);
|
|
186
|
+
const names = (await fs.readdir(outDir))
|
|
187
|
+
.filter((n) => n.startsWith("frame_") && n.endsWith(".jpg"))
|
|
188
|
+
.sort();
|
|
189
|
+
const frames = [];
|
|
190
|
+
for (const [index, name] of names.entries()) {
|
|
191
|
+
frames.push({
|
|
192
|
+
data: new Uint8Array(await fs.readFile(path.join(outDir, name))),
|
|
193
|
+
mimeType: "image/jpeg",
|
|
194
|
+
timeSec: index / fps
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
frames,
|
|
199
|
+
durationSec,
|
|
200
|
+
fps,
|
|
201
|
+
truncated: durationSec === null && frames.length >= maxFrames
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
await fs.rm(dir, { recursive: true, force: true }).catch(() => { });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=video-frames.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-frames.js","sourceRoot":"","sources":["../../src/providers/video-frames.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect a video container from its leading magic bytes.
|
|
3
|
+
*
|
|
4
|
+
* Used when a video reaches a provider without a reliable Content-Type — e.g.
|
|
5
|
+
* asset bytes read from storage.
|
|
6
|
+
*/
|
|
7
|
+
/** Identify a video container; `null` when nothing matches. */
|
|
8
|
+
export declare function sniffVideoMimeOrNull(bytes: Uint8Array): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* As {@link sniffVideoMimeOrNull}, defaulting to mp4 — the container every
|
|
11
|
+
* multimodal provider accepts.
|
|
12
|
+
*/
|
|
13
|
+
export declare function sniffVideoMime(bytes: Uint8Array): string;
|
|
14
|
+
//# sourceMappingURL=video-mime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-mime.d.ts","sourceRoot":"","sources":["../../src/providers/video-mime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAuCrE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAExD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect a video container from its leading magic bytes.
|
|
3
|
+
*
|
|
4
|
+
* Used when a video reaches a provider without a reliable Content-Type — e.g.
|
|
5
|
+
* asset bytes read from storage.
|
|
6
|
+
*/
|
|
7
|
+
/** Identify a video container; `null` when nothing matches. */
|
|
8
|
+
export function sniffVideoMimeOrNull(bytes) {
|
|
9
|
+
// ISO base media file format: <4-byte size> "ftyp" — mp4, m4v and mov all
|
|
10
|
+
// use it; the brand that follows separates QuickTime from mp4.
|
|
11
|
+
if (bytes[4] === 0x66 &&
|
|
12
|
+
bytes[5] === 0x74 &&
|
|
13
|
+
bytes[6] === 0x79 &&
|
|
14
|
+
bytes[7] === 0x70) {
|
|
15
|
+
const brand = String.fromCharCode(bytes[8] ?? 0, bytes[9] ?? 0, bytes[10] ?? 0, bytes[11] ?? 0);
|
|
16
|
+
return brand === "qt " ? "video/quicktime" : "video/mp4";
|
|
17
|
+
}
|
|
18
|
+
// EBML header — Matroska and WebM share it; WebM is the only one Gemini takes.
|
|
19
|
+
if (bytes[0] === 0x1a &&
|
|
20
|
+
bytes[1] === 0x45 &&
|
|
21
|
+
bytes[2] === 0xdf &&
|
|
22
|
+
bytes[3] === 0xa3) {
|
|
23
|
+
return "video/webm";
|
|
24
|
+
}
|
|
25
|
+
// "RIFF" ... "AVI "
|
|
26
|
+
if (bytes[0] === 0x52 &&
|
|
27
|
+
bytes[1] === 0x49 &&
|
|
28
|
+
bytes[2] === 0x46 &&
|
|
29
|
+
bytes[3] === 0x46 &&
|
|
30
|
+
bytes[8] === 0x41 &&
|
|
31
|
+
bytes[9] === 0x56 &&
|
|
32
|
+
bytes[10] === 0x49) {
|
|
33
|
+
return "video/x-msvideo";
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* As {@link sniffVideoMimeOrNull}, defaulting to mp4 — the container every
|
|
39
|
+
* multimodal provider accepts.
|
|
40
|
+
*/
|
|
41
|
+
export function sniffVideoMime(bytes) {
|
|
42
|
+
return sniffVideoMimeOrNull(bytes) ?? "video/mp4";
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=video-mime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-mime.js","sourceRoot":"","sources":["../../src/providers/video-mime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,+DAA+D;AAC/D,MAAM,UAAU,oBAAoB,CAAC,KAAiB;IACpD,0EAA0E;IAC1E,+DAA+D;IAC/D,IACE,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EACjB,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAC/B,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EACb,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EACb,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EACd,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CACf,CAAC;QACF,OAAO,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,WAAW,CAAC;IAC5D,CAAC;IACD,+EAA+E;IAC/E,IACE,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EACjB,CAAC;QACD,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,oBAAoB;IACpB,IACE,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,EAAE,CAAC,KAAK,IAAI,EAClB,CAAC;QACD,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAiB;IAC9C,OAAO,oBAAoB,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { BaseProvider } from "./base-provider.js";
|
|
3
|
+
import type { EncodedAudioResult } from "./types.js";
|
|
4
|
+
export declare const VIDEO_TO_AUDIO_TASK = "video_to_audio";
|
|
5
|
+
/** Source times are seconds in the original asset, before timeline retiming. */
|
|
6
|
+
export declare const VideoToAudioRequest: z.ZodReadonly<z.ZodObject<{
|
|
7
|
+
task: z.ZodLiteral<"video_to_audio">;
|
|
8
|
+
model: z.ZodReadonly<z.ZodObject<{
|
|
9
|
+
id: z.ZodString;
|
|
10
|
+
provider: z.ZodString;
|
|
11
|
+
supportedTasks: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
12
|
+
}, z.core.$strict>>;
|
|
13
|
+
source: z.ZodReadonly<z.ZodObject<{
|
|
14
|
+
assetId: z.ZodString;
|
|
15
|
+
durationSeconds: z.ZodNumber;
|
|
16
|
+
startSeconds: z.ZodNumber;
|
|
17
|
+
endSeconds: z.ZodNumber;
|
|
18
|
+
}, z.core.$strict>>;
|
|
19
|
+
sceneContext: z.ZodString;
|
|
20
|
+
}, z.core.$strict>>;
|
|
21
|
+
export type VideoToAudioRequest = z.infer<typeof VideoToAudioRequest>;
|
|
22
|
+
export type VideoToAudioParams = VideoToAudioRequest & {
|
|
23
|
+
readonly signal?: AbortSignal;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Validate before provider dispatch. `video` contains the original source asset.
|
|
27
|
+
* The provider must condition on the captured window and return encoded audio
|
|
28
|
+
* starting at that window's zero, with its duration. Retiming and timeline
|
|
29
|
+
* placement belong to a future caller. This function never applies the result.
|
|
30
|
+
*/
|
|
31
|
+
export declare function requestVideoToAudio(provider: Pick<BaseProvider, "provider" | "getCapabilities" | "getAvailableVideoModels" | "videoToAudio">, video: Uint8Array, input: unknown, options?: {
|
|
32
|
+
readonly signal?: AbortSignal;
|
|
33
|
+
}): Promise<EncodedAudioResult>;
|
|
34
|
+
//# sourceMappingURL=video-to-audio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-to-audio.d.ts","sourceRoot":"","sources":["../../src/providers/video-to-audio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAEpD,gFAAgF;AAChF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;mBAkCnB,CAAC;AAEd,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACtE,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,GAAG;IACrD,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,iBAAiB,GAAG,yBAAyB,GAAG,cAAc,CAAC,EACzG,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,OAAO,EACd,OAAO,GAAE;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAO,GAC9C,OAAO,CAAC,kBAAkB,CAAC,CA2B7B"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const VIDEO_TO_AUDIO_TASK = "video_to_audio";
|
|
3
|
+
/** Source times are seconds in the original asset, before timeline retiming. */
|
|
4
|
+
export const VideoToAudioRequest = z
|
|
5
|
+
.strictObject({
|
|
6
|
+
task: z.literal(VIDEO_TO_AUDIO_TASK),
|
|
7
|
+
model: z
|
|
8
|
+
.strictObject({
|
|
9
|
+
id: z.string().trim().min(1),
|
|
10
|
+
provider: z.string().trim().min(1),
|
|
11
|
+
supportedTasks: z
|
|
12
|
+
.array(z.string())
|
|
13
|
+
.refine((tasks) => tasks.includes(VIDEO_TO_AUDIO_TASK), "The model must explicitly support video_to_audio")
|
|
14
|
+
.readonly()
|
|
15
|
+
})
|
|
16
|
+
.readonly(),
|
|
17
|
+
source: z
|
|
18
|
+
.strictObject({
|
|
19
|
+
assetId: z.string().trim().min(1),
|
|
20
|
+
durationSeconds: z.number().finite().positive(),
|
|
21
|
+
startSeconds: z.number().finite().nonnegative(),
|
|
22
|
+
endSeconds: z.number().finite().positive()
|
|
23
|
+
})
|
|
24
|
+
.refine((source) => source.endSeconds > source.startSeconds, "The source window must have positive duration")
|
|
25
|
+
.refine((source) => source.endSeconds <= source.durationSeconds, "The source window must fit within the asset duration")
|
|
26
|
+
.readonly(),
|
|
27
|
+
sceneContext: z.string().trim().min(1)
|
|
28
|
+
})
|
|
29
|
+
.readonly();
|
|
30
|
+
/**
|
|
31
|
+
* Validate before provider dispatch. `video` contains the original source asset.
|
|
32
|
+
* The provider must condition on the captured window and return encoded audio
|
|
33
|
+
* starting at that window's zero, with its duration. Retiming and timeline
|
|
34
|
+
* placement belong to a future caller. This function never applies the result.
|
|
35
|
+
*/
|
|
36
|
+
export async function requestVideoToAudio(provider, video, input, options = {}) {
|
|
37
|
+
const request = VideoToAudioRequest.parse(input);
|
|
38
|
+
if (!(video instanceof Uint8Array) || video.byteLength === 0) {
|
|
39
|
+
throw new Error("video_to_audio requires nonempty source video bytes");
|
|
40
|
+
}
|
|
41
|
+
if (request.model.provider !== provider.provider) {
|
|
42
|
+
throw new Error("The video_to_audio model belongs to a different provider");
|
|
43
|
+
}
|
|
44
|
+
if (!provider.getCapabilities().includes(VIDEO_TO_AUDIO_TASK)) {
|
|
45
|
+
throw new Error(`${provider.provider} does not support video_to_audio`);
|
|
46
|
+
}
|
|
47
|
+
options.signal?.throwIfAborted();
|
|
48
|
+
const model = (await provider.getAvailableVideoModels()).find((candidate) => candidate.id === request.model.id && candidate.provider === provider.provider);
|
|
49
|
+
if (!model?.supportedTasks?.includes(VIDEO_TO_AUDIO_TASK)) {
|
|
50
|
+
throw new Error(`Model ${request.model.id} does not support video_to_audio in the provider catalog`);
|
|
51
|
+
}
|
|
52
|
+
options.signal?.throwIfAborted();
|
|
53
|
+
const validatedRequest = {
|
|
54
|
+
...request,
|
|
55
|
+
model: { ...request.model, supportedTasks: [...model.supportedTasks] }
|
|
56
|
+
};
|
|
57
|
+
if (options.signal) {
|
|
58
|
+
return provider.videoToAudio(video, { ...validatedRequest, signal: options.signal });
|
|
59
|
+
}
|
|
60
|
+
return provider.videoToAudio(video, validatedRequest);
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=video-to-audio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-to-audio.js","sourceRoot":"","sources":["../../src/providers/video-to-audio.ts"],"names":[],"mappings":"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"}
|