@nodetool-ai/agents 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.nodetool-build-stamp +1 -1
- package/dist/analysis/audio-dsp.d.ts +3 -2
- package/dist/analysis/audio-dsp.d.ts.map +1 -1
- package/dist/analysis/audio-dsp.js +11 -8
- package/dist/analysis/audio-dsp.js.map +1 -1
- package/dist/analysis/media-decode.d.ts +13 -0
- package/dist/analysis/media-decode.d.ts.map +1 -1
- package/dist/analysis/media-decode.js +33 -6
- package/dist/analysis/media-decode.js.map +1 -1
- package/dist/author-graph.d.ts +2 -3
- package/dist/author-graph.d.ts.map +1 -1
- package/dist/author-graph.js +3 -5
- package/dist/author-graph.js.map +1 -1
- package/dist/browser-gate.d.ts +2 -2
- package/dist/browser-gate.js +2 -2
- package/dist/capabilities/GamePublishRequest.d.ts +14 -0
- package/dist/capabilities/GamePublishRequest.d.ts.map +1 -0
- package/dist/capabilities/GamePublishRequest.js +2 -0
- package/dist/capabilities/GamePublishRequest.js.map +1 -0
- package/dist/capabilities/adapters.d.ts +4 -13
- package/dist/capabilities/adapters.d.ts.map +1 -1
- package/dist/capabilities/adapters.js +9 -14
- package/dist/capabilities/adapters.js.map +1 -1
- package/dist/capabilities/agent-activity.d.ts +27 -0
- package/dist/capabilities/agent-activity.d.ts.map +1 -0
- package/dist/capabilities/agent-activity.js +103 -0
- package/dist/capabilities/agent-activity.js.map +1 -0
- package/dist/capabilities/agentic-storyboard-finish.d.ts +67 -0
- package/dist/capabilities/agentic-storyboard-finish.d.ts.map +1 -0
- package/dist/capabilities/agentic-storyboard-finish.js +1321 -0
- package/dist/capabilities/agentic-storyboard-finish.js.map +1 -0
- package/dist/capabilities/agents.d.ts +5 -2
- package/dist/capabilities/agents.d.ts.map +1 -1
- package/dist/capabilities/agents.js +14 -4
- package/dist/capabilities/agents.js.map +1 -1
- package/dist/capabilities/agents.specs.d.ts +3 -0
- package/dist/capabilities/agents.specs.d.ts.map +1 -1
- package/dist/capabilities/agents.specs.js +71 -1
- package/dist/capabilities/agents.specs.js.map +1 -1
- package/dist/capabilities/analysis.d.ts.map +1 -1
- package/dist/capabilities/analysis.js +33 -22
- package/dist/capabilities/analysis.js.map +1 -1
- package/dist/capabilities/analysis.specs.js +2 -2
- package/dist/capabilities/analysis.specs.js.map +1 -1
- package/dist/capabilities/apps.d.ts.map +1 -1
- package/dist/capabilities/apps.js +5 -3
- package/dist/capabilities/apps.js.map +1 -1
- package/dist/capabilities/args.d.ts +2 -5
- package/dist/capabilities/args.d.ts.map +1 -1
- package/dist/capabilities/args.js +2 -5
- package/dist/capabilities/args.js.map +1 -1
- package/dist/capabilities/browser.d.ts +1 -1
- package/dist/capabilities/browser.js +1 -1
- package/dist/capabilities/browser.specs.d.ts +1 -1
- package/dist/capabilities/browser.specs.js +1 -1
- package/dist/capabilities/code.d.ts +5 -0
- package/dist/capabilities/code.d.ts.map +1 -1
- package/dist/capabilities/code.js +128 -89
- package/dist/capabilities/code.js.map +1 -1
- package/dist/capabilities/errors.d.ts +19 -0
- package/dist/capabilities/errors.d.ts.map +1 -0
- package/dist/capabilities/errors.js +109 -0
- package/dist/capabilities/errors.js.map +1 -0
- package/dist/capabilities/errors.specs.d.ts +11 -0
- package/dist/capabilities/errors.specs.d.ts.map +1 -0
- package/dist/capabilities/errors.specs.js +100 -0
- package/dist/capabilities/errors.specs.js.map +1 -0
- package/dist/capabilities/example-timelines.d.ts.map +1 -1
- package/dist/capabilities/example-timelines.js +52 -10
- package/dist/capabilities/example-timelines.js.map +1 -1
- package/dist/capabilities/example-timelines.specs.d.ts +1 -0
- package/dist/capabilities/example-timelines.specs.d.ts.map +1 -1
- package/dist/capabilities/example-timelines.specs.js +21 -3
- package/dist/capabilities/example-timelines.specs.js.map +1 -1
- package/dist/capabilities/finish-storyboard.d.ts +5 -0
- package/dist/capabilities/finish-storyboard.d.ts.map +1 -0
- package/dist/capabilities/finish-storyboard.js +278 -0
- package/dist/capabilities/finish-storyboard.js.map +1 -0
- package/dist/capabilities/game-asset-source.js +1 -1
- package/dist/capabilities/game-asset-source.js.map +1 -1
- package/dist/capabilities/game.d.ts +14 -2
- package/dist/capabilities/game.d.ts.map +1 -1
- package/dist/capabilities/game.js +209 -39
- package/dist/capabilities/game.js.map +1 -1
- package/dist/capabilities/game.specs.d.ts +2 -0
- package/dist/capabilities/game.specs.d.ts.map +1 -1
- package/dist/capabilities/game.specs.js +25 -11
- package/dist/capabilities/game.specs.js.map +1 -1
- package/dist/capabilities/game3d.d.ts +17 -0
- package/dist/capabilities/game3d.d.ts.map +1 -0
- package/dist/capabilities/game3d.js +433 -0
- package/dist/capabilities/game3d.js.map +1 -0
- package/dist/capabilities/gate-from-context.d.ts +1 -1
- package/dist/capabilities/gate-from-context.js +1 -1
- package/dist/capabilities/generations.d.ts +2 -0
- package/dist/capabilities/generations.d.ts.map +1 -1
- package/dist/capabilities/generations.js +7 -2
- package/dist/capabilities/generations.js.map +1 -1
- package/dist/capabilities/index.d.ts +2 -2
- package/dist/capabilities/index.d.ts.map +1 -1
- package/dist/capabilities/index.js +2 -2
- package/dist/capabilities/index.js.map +1 -1
- package/dist/capabilities/invoke.d.ts +14 -25
- package/dist/capabilities/invoke.d.ts.map +1 -1
- package/dist/capabilities/invoke.js +72 -35
- package/dist/capabilities/invoke.js.map +1 -1
- package/dist/capabilities/jobs.d.ts.map +1 -1
- package/dist/capabilities/jobs.js +47 -3
- package/dist/capabilities/jobs.js.map +1 -1
- package/dist/capabilities/jobs.specs.d.ts.map +1 -1
- package/dist/capabilities/jobs.specs.js +3 -1
- package/dist/capabilities/jobs.specs.js.map +1 -1
- package/dist/capabilities/js-scripts.d.ts +19 -1
- package/dist/capabilities/js-scripts.d.ts.map +1 -1
- package/dist/capabilities/js-scripts.js +109 -2
- package/dist/capabilities/js-scripts.js.map +1 -1
- package/dist/capabilities/js-scripts.specs.d.ts +2 -0
- package/dist/capabilities/js-scripts.specs.d.ts.map +1 -1
- package/dist/capabilities/js-scripts.specs.js +50 -0
- package/dist/capabilities/js-scripts.specs.js.map +1 -1
- package/dist/capabilities/lazy-tool.d.ts +23 -24
- package/dist/capabilities/lazy-tool.d.ts.map +1 -1
- package/dist/capabilities/lazy-tool.js +29 -35
- package/dist/capabilities/lazy-tool.js.map +1 -1
- package/dist/capabilities/legacy-tools.d.ts +15 -0
- package/dist/capabilities/legacy-tools.d.ts.map +1 -0
- package/dist/capabilities/legacy-tools.js +98 -0
- package/dist/capabilities/legacy-tools.js.map +1 -0
- package/dist/capabilities/media.d.ts +0 -9
- package/dist/capabilities/media.d.ts.map +1 -1
- package/dist/capabilities/media.js +301 -260
- package/dist/capabilities/media.js.map +1 -1
- package/dist/capabilities/models.d.ts +2 -2
- package/dist/capabilities/models.d.ts.map +1 -1
- package/dist/capabilities/models.js +5 -3
- package/dist/capabilities/models.js.map +1 -1
- package/dist/capabilities/registry.d.ts +2 -0
- package/dist/capabilities/registry.d.ts.map +1 -1
- package/dist/capabilities/registry.js +28 -0
- package/dist/capabilities/registry.js.map +1 -1
- package/dist/capabilities/run-agent.d.ts +19 -0
- package/dist/capabilities/run-agent.d.ts.map +1 -0
- package/dist/capabilities/run-agent.js +183 -0
- package/dist/capabilities/run-agent.js.map +1 -0
- package/dist/capabilities/runs.d.ts +9 -0
- package/dist/capabilities/runs.d.ts.map +1 -0
- package/dist/capabilities/runs.js +46 -0
- package/dist/capabilities/runs.js.map +1 -0
- package/dist/capabilities/runs.specs.d.ts +39 -0
- package/dist/capabilities/runs.specs.d.ts.map +1 -0
- package/dist/capabilities/runs.specs.js +52 -0
- package/dist/capabilities/runs.specs.js.map +1 -0
- package/dist/capabilities/scripts.d.ts.map +1 -1
- package/dist/capabilities/scripts.js +11 -5
- package/dist/capabilities/scripts.js.map +1 -1
- package/dist/capabilities/sketches.d.ts.map +1 -1
- package/dist/capabilities/sketches.js +4 -2
- package/dist/capabilities/sketches.js.map +1 -1
- package/dist/capabilities/skills.d.ts.map +1 -1
- package/dist/capabilities/skills.js +22 -2
- package/dist/capabilities/skills.js.map +1 -1
- package/dist/capabilities/storyboard-layout-check.d.ts +33 -0
- package/dist/capabilities/storyboard-layout-check.d.ts.map +1 -0
- package/dist/capabilities/storyboard-layout-check.js +229 -0
- package/dist/capabilities/storyboard-layout-check.js.map +1 -0
- package/dist/capabilities/storyboard-measured-sources.d.ts +10 -0
- package/dist/capabilities/storyboard-measured-sources.d.ts.map +1 -0
- package/dist/capabilities/storyboard-measured-sources.js +67 -0
- package/dist/capabilities/storyboard-measured-sources.js.map +1 -0
- package/dist/capabilities/storyboard-review-times.d.ts +4 -0
- package/dist/capabilities/storyboard-review-times.d.ts.map +1 -0
- package/dist/capabilities/storyboard-review-times.js +39 -0
- package/dist/capabilities/storyboard-review-times.js.map +1 -0
- package/dist/capabilities/storyboards.d.ts +2 -18
- package/dist/capabilities/storyboards.d.ts.map +1 -1
- package/dist/capabilities/storyboards.js +315 -94
- package/dist/capabilities/storyboards.js.map +1 -1
- package/dist/capabilities/storyboards.specs.d.ts +3 -0
- package/dist/capabilities/storyboards.specs.d.ts.map +1 -1
- package/dist/capabilities/storyboards.specs.js +42 -3
- package/dist/capabilities/storyboards.specs.js.map +1 -1
- package/dist/capabilities/timeline-bridge.d.ts +359 -0
- package/dist/capabilities/timeline-bridge.d.ts.map +1 -0
- package/dist/capabilities/timeline-bridge.js +1016 -0
- package/dist/capabilities/timeline-bridge.js.map +1 -0
- package/dist/capabilities/timeline-clip-frames.d.ts +17 -0
- package/dist/capabilities/timeline-clip-frames.d.ts.map +1 -0
- package/dist/capabilities/timeline-clip-frames.js +84 -0
- package/dist/capabilities/timeline-clip-frames.js.map +1 -0
- package/dist/capabilities/timeline-media-edit.d.ts +8 -0
- package/dist/capabilities/timeline-media-edit.d.ts.map +1 -0
- package/dist/capabilities/timeline-media-edit.js +94 -0
- package/dist/capabilities/timeline-media-edit.js.map +1 -0
- package/dist/capabilities/timeline-native-media.d.ts.map +1 -1
- package/dist/capabilities/timeline-native-media.js +40 -0
- package/dist/capabilities/timeline-native-media.js.map +1 -1
- package/dist/capabilities/timelines.d.ts +64 -4
- package/dist/capabilities/timelines.d.ts.map +1 -1
- package/dist/capabilities/timelines.js +566 -67
- package/dist/capabilities/timelines.js.map +1 -1
- package/dist/capabilities/timelines.specs.d.ts +8 -0
- package/dist/capabilities/timelines.specs.d.ts.map +1 -1
- package/dist/capabilities/timelines.specs.js +173 -8
- package/dist/capabilities/timelines.specs.js.map +1 -1
- package/dist/capabilities/types.d.ts +3 -1
- package/dist/capabilities/types.d.ts.map +1 -1
- package/dist/capabilities/types.js.map +1 -1
- package/dist/capabilities/ui.d.ts.map +1 -1
- package/dist/capabilities/ui.js +24 -2
- package/dist/capabilities/ui.js.map +1 -1
- package/dist/capabilities/workflows.d.ts.map +1 -1
- package/dist/capabilities/workflows.js +53 -26
- package/dist/capabilities/workflows.js.map +1 -1
- package/dist/capabilities/workflows.specs.d.ts.map +1 -1
- package/dist/capabilities/workflows.specs.js +7 -1
- package/dist/capabilities/workflows.specs.js.map +1 -1
- package/dist/codeact/action-diagnostics.d.ts.map +1 -1
- package/dist/codeact/action-diagnostics.js +51 -1
- package/dist/codeact/action-diagnostics.js.map +1 -1
- package/dist/codeact/codeact-executor.d.ts.map +1 -1
- package/dist/codeact/codeact-executor.js +16 -8
- package/dist/codeact/codeact-executor.js.map +1 -1
- package/dist/codeact/compact-ids.d.ts.map +1 -1
- package/dist/codeact/compact-ids.js +5 -1
- package/dist/codeact/compact-ids.js.map +1 -1
- package/dist/codeact/graph-model.d.ts +1 -1
- package/dist/codeact/graph-model.d.ts.map +1 -1
- package/dist/codeact/graph-model.js +2 -3
- package/dist/codeact/graph-model.js.map +1 -1
- package/dist/codeact/nodetool-api.d.ts +1 -1
- package/dist/codeact/nodetool-api.d.ts.map +1 -1
- package/dist/codeact/nodetool-api.js +202 -284
- package/dist/codeact/nodetool-api.js.map +1 -1
- package/dist/codeact/tool-api.d.ts +6 -3
- package/dist/codeact/tool-api.d.ts.map +1 -1
- package/dist/codeact/tool-api.js +22 -15
- package/dist/codeact/tool-api.js.map +1 -1
- package/dist/evals/codeact-api-cases.d.ts.map +1 -1
- package/dist/evals/codeact-api-cases.js +2 -0
- package/dist/evals/codeact-api-cases.js.map +1 -1
- package/dist/evals/codeact-api-runs.d.ts +3 -0
- package/dist/evals/codeact-api-runs.d.ts.map +1 -0
- package/dist/evals/codeact-api-runs.js +33 -0
- package/dist/evals/codeact-api-runs.js.map +1 -0
- package/dist/evals/surfaces/sketch.d.ts +2 -0
- package/dist/evals/surfaces/sketch.d.ts.map +1 -1
- package/dist/evals/surfaces/sketch.js +11 -3
- package/dist/evals/surfaces/sketch.js.map +1 -1
- package/dist/evals/surfaces/timeline.d.ts +4 -357
- package/dist/evals/surfaces/timeline.d.ts.map +1 -1
- package/dist/evals/surfaces/timeline.js +9 -2621
- package/dist/evals/surfaces/timeline.js.map +1 -1
- package/dist/evals/tool-loop-bridge.d.ts +4 -0
- package/dist/evals/tool-loop-bridge.d.ts.map +1 -1
- package/dist/evals/tool-loop-bridge.js.map +1 -1
- package/dist/evals/tool-loop-eval.d.ts +2 -0
- package/dist/evals/tool-loop-eval.d.ts.map +1 -1
- package/dist/evals/tool-loop-eval.js +6 -1
- package/dist/evals/tool-loop-eval.js.map +1 -1
- package/dist/evals/tool-loop-permission.d.ts +1 -15
- package/dist/evals/tool-loop-permission.d.ts.map +1 -1
- package/dist/evals/tool-loop-permission.js +23 -41
- package/dist/evals/tool-loop-permission.js.map +1 -1
- package/dist/game-authoring.d.ts +4737 -0
- package/dist/game-authoring.d.ts.map +1 -0
- package/dist/game-authoring.js +146 -0
- package/dist/game-authoring.js.map +1 -0
- package/dist/game-code-bake.d.ts +26 -0
- package/dist/game-code-bake.d.ts.map +1 -0
- package/dist/game-code-bake.js +98 -0
- package/dist/game-code-bake.js.map +1 -0
- package/dist/game-examples.d.ts +872 -16
- package/dist/game-examples.d.ts.map +1 -1
- package/dist/game-examples.js +5 -4
- package/dist/game-examples.js.map +1 -1
- package/dist/index.d.ts +15 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -3
- package/dist/index.js.map +1 -1
- package/dist/js-sandbox-worker/engine.d.ts +4 -0
- package/dist/js-sandbox-worker/engine.d.ts.map +1 -0
- package/dist/js-sandbox-worker/engine.js +45 -0
- package/dist/js-sandbox-worker/engine.js.map +1 -0
- package/dist/js-sandbox-worker/host.js +1 -1
- package/dist/js-sandbox-worker/host.js.map +1 -1
- package/dist/js-sandbox-worker/interpreter.d.ts +1 -1
- package/dist/js-sandbox-worker/interpreter.d.ts.map +1 -1
- package/dist/js-sandbox-worker/interpreter.js +94 -2
- package/dist/js-sandbox-worker/interpreter.js.map +1 -1
- package/dist/js-sandbox-worker/worker-entry.d.ts.map +1 -1
- package/dist/js-sandbox-worker/worker-entry.js +3 -2
- package/dist/js-sandbox-worker/worker-entry.js.map +1 -1
- package/dist/js-sandbox.d.ts +2 -0
- package/dist/js-sandbox.d.ts.map +1 -1
- package/dist/js-sandbox.js +56 -11
- package/dist/js-sandbox.js.map +1 -1
- package/dist/js-script-app-runner.d.ts +2 -0
- package/dist/js-script-app-runner.d.ts.map +1 -1
- package/dist/js-script-app-runner.js +8 -3
- package/dist/js-script-app-runner.js.map +1 -1
- package/dist/js-script-sandbox.d.ts +12 -18
- package/dist/js-script-sandbox.d.ts.map +1 -1
- package/dist/js-script-sandbox.js +3 -49
- package/dist/js-script-sandbox.js.map +1 -1
- package/dist/prompts/product-knowledge.d.ts +1 -1
- package/dist/prompts/product-knowledge.d.ts.map +1 -1
- package/dist/prompts/product-knowledge.js +82 -41
- package/dist/prompts/product-knowledge.js.map +1 -1
- package/dist/sandbox-pack-resolution.d.ts +21 -0
- package/dist/sandbox-pack-resolution.d.ts.map +1 -0
- package/dist/sandbox-pack-resolution.js +42 -0
- package/dist/sandbox-pack-resolution.js.map +1 -0
- package/dist/sandbox-toolbelt.d.ts +3 -1
- package/dist/sandbox-toolbelt.d.ts.map +1 -1
- package/dist/sandbox-toolbelt.js +8 -2
- package/dist/sandbox-toolbelt.js.map +1 -1
- package/dist/skill-prompt.d.ts +11 -1
- package/dist/skill-prompt.d.ts.map +1 -1
- package/dist/skill-prompt.js +17 -6
- package/dist/skill-prompt.js.map +1 -1
- package/dist/system-skills.d.ts +7 -1
- package/dist/system-skills.d.ts.map +1 -1
- package/dist/system-skills.js +2 -2
- package/dist/system-skills.js.map +1 -1
- package/dist/timeline-capture.d.ts +21 -0
- package/dist/timeline-capture.d.ts.map +1 -0
- package/dist/timeline-capture.js +564 -0
- package/dist/timeline-capture.js.map +1 -0
- package/dist/timeline-code-bake.d.ts +75 -0
- package/dist/timeline-code-bake.d.ts.map +1 -0
- package/dist/timeline-code-bake.js +327 -0
- package/dist/timeline-code-bake.js.map +1 -0
- package/dist/timeline-preview/frames.d.ts +26 -0
- package/dist/timeline-preview/frames.d.ts.map +1 -1
- package/dist/timeline-preview/frames.js +155 -70
- package/dist/timeline-preview/frames.js.map +1 -1
- package/dist/tools/base-tool.d.ts +1 -0
- package/dist/tools/base-tool.d.ts.map +1 -1
- package/dist/tools/base-tool.js +1 -1
- package/dist/tools/base-tool.js.map +1 -1
- package/dist/tools/builtin-tools.d.ts.map +1 -1
- package/dist/tools/builtin-tools.js +13 -0
- package/dist/tools/builtin-tools.js.map +1 -1
- package/dist/tools/external-capability-tools.d.ts +1 -1
- package/dist/tools/external-capability-tools.js +1 -1
- package/dist/tools/mcp-tool-support.d.ts +10 -9
- package/dist/tools/mcp-tool-support.d.ts.map +1 -1
- package/dist/tools/mcp-tool-support.js +14 -13
- package/dist/tools/mcp-tool-support.js.map +1 -1
- package/dist/tools/mcp-tools.d.ts +6 -4
- package/dist/tools/mcp-tools.d.ts.map +1 -1
- package/dist/tools/mcp-tools.js +65 -62
- package/dist/tools/mcp-tools.js.map +1 -1
- package/dist/tools/tool-permissions.d.ts +1 -1
- package/dist/tools/tool-permissions.js +1 -1
- package/package.json +24 -22
- package/dist/capabilities/gate-tools.d.ts +0 -18
- package/dist/capabilities/gate-tools.d.ts.map +0 -1
- package/dist/capabilities/gate-tools.js +0 -66
- package/dist/capabilities/gate-tools.js.map +0 -1
- package/dist/tsconfig.tests.tmp.tsbuildinfo +0 -1
|
@@ -22,7 +22,7 @@ import { Buffer } from "node:buffer";
|
|
|
22
22
|
import { randomInt, randomUUID } from "node:crypto";
|
|
23
23
|
import { mkdir, readFile } from "node:fs/promises";
|
|
24
24
|
import path from "node:path";
|
|
25
|
-
import { loadMediaRefBytes } from "@nodetool-ai/runtime";
|
|
25
|
+
import { currentGenerationReceipt, loadMediaRefBytes } from "@nodetool-ai/runtime";
|
|
26
26
|
import { getMaxLocalUploadBytes } from "@nodetool-ai/storage";
|
|
27
27
|
import { backgroundGenerationLimitError, startBackgroundGeneration } from "./background-generation.js";
|
|
28
28
|
import { HostBinaryMissingError, clampTimeoutSeconds, mimeFromFilename, runHostBinary } from "../host-binaries.js";
|
|
@@ -31,7 +31,7 @@ import { assertFetchUrlAllowed, assertResolvedHostAllowed } from "../network-gua
|
|
|
31
31
|
import { encodeBase64 as encodeMediaBase64 } from "../sandbox-bytes.js";
|
|
32
32
|
import { imagePixelSize, sniffImageFormat } from "../sandbox-media.js";
|
|
33
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";
|
|
34
|
+
import { MIME_TO_EXT, inferImageMime, persistOutput, timestampedName } from "../tools/asset-persist.js";
|
|
35
35
|
import { persistBinaryOutput } from "../tools/binary-output.js";
|
|
36
36
|
import { extractJSON, extractJSONAllowingTruncation } from "../utils/json-parser.js";
|
|
37
37
|
import { isYtDlpEnabled } from "../yt-dlp-gate.js";
|
|
@@ -267,16 +267,6 @@ async function finishOutput(context, bytes, assets, opts) {
|
|
|
267
267
|
}
|
|
268
268
|
return result;
|
|
269
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
270
|
/** What a `background: true` call answers with. */
|
|
281
271
|
function backgroundReceipt(id, spec) {
|
|
282
272
|
return {
|
|
@@ -742,6 +732,9 @@ const videoFromReferences = {
|
|
|
742
732
|
});
|
|
743
733
|
}
|
|
744
734
|
};
|
|
735
|
+
// ---------------------------------------------------------------------------
|
|
736
|
+
// generate_speech
|
|
737
|
+
// ---------------------------------------------------------------------------
|
|
745
738
|
function int16ToUint8(samples) {
|
|
746
739
|
const bytes = new Uint8Array(samples.byteLength);
|
|
747
740
|
const view = new DataView(bytes.buffer);
|
|
@@ -840,228 +833,244 @@ async function encodedSpeech(context, m, params, generation) {
|
|
|
840
833
|
return await provider.textToSpeechEncoded({
|
|
841
834
|
text: params.text,
|
|
842
835
|
model: m.model,
|
|
843
|
-
voice: params.voice,
|
|
844
|
-
speed: params.speed,
|
|
836
|
+
voice: isString(params.voice) ? params.voice : undefined,
|
|
837
|
+
speed: typeof params.speed === "number" ? params.speed : undefined,
|
|
845
838
|
audioFormat: params.audioFormat
|
|
846
839
|
});
|
|
847
840
|
}
|
|
848
841
|
throw new Error("this runtime's context has no encoded text_to_speech path");
|
|
849
842
|
}
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
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
|
|
843
|
+
async function speechAudio(context, provider, m, params, signal, outputFile) {
|
|
844
|
+
signal.throwIfAborted();
|
|
845
|
+
const providerParams = {
|
|
846
|
+
text: params.text,
|
|
847
|
+
model: m.model,
|
|
848
|
+
voice: isString(params.voice) ? params.voice : undefined,
|
|
849
|
+
speed: typeof params.speed === "number" ? params.speed : undefined,
|
|
850
|
+
audioFormat: params.audioFormat,
|
|
851
|
+
signal
|
|
852
|
+
};
|
|
853
|
+
let encodedError;
|
|
854
|
+
try {
|
|
855
|
+
const encoded = provider
|
|
856
|
+
? await provider.textToSpeechEncoded(providerParams)
|
|
857
|
+
: await encodedSpeech(context, m, params);
|
|
858
|
+
signal.throwIfAborted();
|
|
859
|
+
if (encoded?.data && encoded.data.length > 0) {
|
|
860
|
+
return {
|
|
861
|
+
data: encoded.data,
|
|
862
|
+
mimeType: encoded.mimeType ?? "audio/mpeg",
|
|
863
|
+
outputFile
|
|
883
864
|
};
|
|
884
|
-
const started = startBackgroundGeneration(context, () => encodedSpeech(context, m, speechParams, generation));
|
|
885
|
-
if (!started) {
|
|
886
|
-
return backgroundGenerationLimitError();
|
|
887
|
-
}
|
|
888
|
-
return backgroundReceipt(generationId, spec);
|
|
889
865
|
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
866
|
+
}
|
|
867
|
+
catch (error) {
|
|
868
|
+
if (signal.aborted || currentGenerationReceipt()?.provider_request_id) {
|
|
869
|
+
throw error;
|
|
870
|
+
}
|
|
871
|
+
encodedError = error;
|
|
872
|
+
}
|
|
873
|
+
if (currentGenerationReceipt()?.provider_request_id) {
|
|
874
|
+
throw new Error("The accepted speech request returned no audio; recover that request before submitting another.");
|
|
875
|
+
}
|
|
876
|
+
const parts = [];
|
|
877
|
+
let pcmOnly = true;
|
|
878
|
+
let mimeType;
|
|
879
|
+
let sampleRate;
|
|
880
|
+
try {
|
|
881
|
+
const stream = provider
|
|
882
|
+
? provider.textToSpeech(providerParams)
|
|
883
|
+
: context.streamProviderPrediction({
|
|
884
|
+
provider: m.provider,
|
|
885
|
+
capability: "text_to_speech",
|
|
886
|
+
model: m.model,
|
|
887
|
+
params: { ...providerParams, signal }
|
|
888
|
+
});
|
|
889
|
+
for await (const item of stream) {
|
|
890
|
+
signal.throwIfAborted();
|
|
891
|
+
if (!isRecord(item)) {
|
|
892
|
+
continue;
|
|
913
893
|
}
|
|
914
|
-
|
|
915
|
-
|
|
894
|
+
const chunk = item;
|
|
895
|
+
if (chunk.data instanceof Uint8Array || isString(chunk.data)) {
|
|
896
|
+
const data = chunk.data instanceof Uint8Array
|
|
897
|
+
? chunk.data
|
|
898
|
+
: Buffer.from(chunk.data, "base64");
|
|
899
|
+
if (data.length > 0) {
|
|
900
|
+
parts.push(data);
|
|
901
|
+
}
|
|
902
|
+
if (isString(chunk.mimeType)) {
|
|
903
|
+
mimeType = chunk.mimeType;
|
|
904
|
+
}
|
|
905
|
+
pcmOnly = false;
|
|
916
906
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
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
|
-
}
|
|
907
|
+
else {
|
|
908
|
+
if (chunk.sampleRate !== undefined) {
|
|
909
|
+
if (typeof chunk.sampleRate !== "number" ||
|
|
910
|
+
!Number.isInteger(chunk.sampleRate) ||
|
|
911
|
+
chunk.sampleRate <= 0 ||
|
|
912
|
+
chunk.sampleRate > 0xffffffff / 2) {
|
|
913
|
+
throw new Error("TTS returned an invalid PCM sample rate");
|
|
957
914
|
}
|
|
958
|
-
|
|
959
|
-
|
|
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)})`);
|
|
915
|
+
if (sampleRate !== undefined && sampleRate !== chunk.sampleRate) {
|
|
916
|
+
throw new Error("TTS changed PCM sample rate during the stream");
|
|
966
917
|
}
|
|
967
|
-
|
|
918
|
+
sampleRate = chunk.sampleRate;
|
|
968
919
|
}
|
|
969
|
-
if (
|
|
970
|
-
|
|
971
|
-
error: encodedError
|
|
972
|
-
? `Provider returned no audio data: ${encodedError}`
|
|
973
|
-
: "Provider returned no audio data"
|
|
974
|
-
};
|
|
920
|
+
if (chunk.samples instanceof Int16Array && chunk.samples.length > 0) {
|
|
921
|
+
parts.push(int16ToUint8(chunk.samples));
|
|
975
922
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
catch (error) {
|
|
927
|
+
if (encodedError) {
|
|
928
|
+
throw new Error(`${encodedError instanceof Error ? encodedError.message : String(encodedError)} (the streaming fallback then failed too: ${error instanceof Error ? error.message : String(error)})`);
|
|
929
|
+
}
|
|
930
|
+
throw error;
|
|
931
|
+
}
|
|
932
|
+
signal.throwIfAborted();
|
|
933
|
+
const merged = concatUint8(parts);
|
|
934
|
+
if (merged.length === 0) {
|
|
935
|
+
throw new Error("Provider returned no audio data");
|
|
936
|
+
}
|
|
937
|
+
if (pcmOnly && !mimeType) {
|
|
938
|
+
if (merged.length < 2 || merged.length % 2 !== 0) {
|
|
939
|
+
throw new Error("TTS produced no complete audio samples");
|
|
940
|
+
}
|
|
941
|
+
const finalPath = outputFile
|
|
942
|
+
? path.join(path.dirname(outputFile), `${path.basename(outputFile, path.extname(outputFile))}.wav`)
|
|
943
|
+
: undefined;
|
|
944
|
+
return {
|
|
945
|
+
data: wrapPcmAsWav(merged, sampleRate ?? 24000),
|
|
946
|
+
mimeType: "audio/wav",
|
|
947
|
+
outputFile: finalPath
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
return { data: merged, mimeType: mimeType ?? "audio/mpeg", outputFile };
|
|
951
|
+
}
|
|
952
|
+
function runAudioGeneration(context, req, spec, params, call) {
|
|
953
|
+
const work = async () => {
|
|
954
|
+
let saved;
|
|
955
|
+
const result = await context.runGenerationWith(req, async (provider, signal) => {
|
|
956
|
+
const audio = await call(provider, signal);
|
|
957
|
+
if (audio.outputFile && req.persist) {
|
|
958
|
+
req.persist.name = path.basename(audio.outputFile);
|
|
959
|
+
}
|
|
960
|
+
return audio;
|
|
961
|
+
}, {
|
|
962
|
+
finalizeOutput: async (output, assets) => {
|
|
963
|
+
if (!isRecord(output) ||
|
|
964
|
+
!(output.data instanceof Uint8Array) ||
|
|
965
|
+
!isString(output.mimeType)) {
|
|
966
|
+
throw new Error("Provider returned invalid audio output");
|
|
988
967
|
}
|
|
989
|
-
|
|
990
|
-
|
|
968
|
+
const mime = output.mimeType;
|
|
969
|
+
const first = assets[0];
|
|
970
|
+
saved = { bytes: output.data.length, mime_type: mime };
|
|
971
|
+
if (first?.asset_id) {
|
|
972
|
+
saved.asset_id = first.asset_id;
|
|
973
|
+
saved.asset_uri = first.uri;
|
|
974
|
+
saved.url = first.uri;
|
|
991
975
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
976
|
+
const outputFile = isString(output.outputFile)
|
|
977
|
+
? output.outputFile
|
|
978
|
+
: undefined;
|
|
979
|
+
if (outputFile || !saved.asset_id) {
|
|
980
|
+
const destination = outputFile ??
|
|
981
|
+
timestampedName(spec.namePrefix, MIME_TO_EXT[mime] ?? "bin");
|
|
982
|
+
if (!context.workspace) {
|
|
983
|
+
return {
|
|
984
|
+
status: "failed",
|
|
985
|
+
path: destination,
|
|
986
|
+
error: `Could not deliver audio to "${destination}": no workspace is available.`
|
|
987
|
+
};
|
|
999
988
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
989
|
+
try {
|
|
990
|
+
await context.workspace.write(destination, output.data, mime);
|
|
991
|
+
}
|
|
992
|
+
catch (error) {
|
|
993
|
+
return {
|
|
994
|
+
status: "failed",
|
|
995
|
+
path: destination,
|
|
996
|
+
error: error instanceof Error ? error.message : String(error)
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
saved.path = destination;
|
|
1000
|
+
return { status: "completed", path: destination };
|
|
1001
|
+
}
|
|
1002
|
+
return { status: "completed" };
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
const response = {
|
|
1006
|
+
type: "audio",
|
|
1007
|
+
provider: spec.m.provider,
|
|
1008
|
+
model: spec.m.model,
|
|
1009
|
+
generation_id: result.id,
|
|
1010
|
+
...saved
|
|
1011
|
+
};
|
|
1012
|
+
if (result.delivery) {
|
|
1013
|
+
response.delivery = result.delivery;
|
|
1013
1014
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1015
|
+
return response;
|
|
1016
|
+
};
|
|
1017
|
+
if (params.background === true) {
|
|
1018
|
+
if (!startBackgroundGeneration(context, work)) {
|
|
1019
|
+
return backgroundGenerationLimitError();
|
|
1019
1020
|
}
|
|
1021
|
+
return backgroundReceipt(req.id ?? "", spec);
|
|
1022
|
+
}
|
|
1023
|
+
return work().catch((error) => ({
|
|
1024
|
+
...predictionError(spec.capability, spec.m, error),
|
|
1025
|
+
generation_id: req.id
|
|
1026
|
+
}));
|
|
1027
|
+
}
|
|
1028
|
+
const generateSpeech = {
|
|
1029
|
+
spec: generateSpeechSpec,
|
|
1030
|
+
impl: async (run, params) => {
|
|
1031
|
+
const m = parseModelArgs(params);
|
|
1032
|
+
if ("error" in m) {
|
|
1033
|
+
return m;
|
|
1034
|
+
}
|
|
1035
|
+
const text = params.text;
|
|
1036
|
+
if (!isNonEmptyString(text)) {
|
|
1037
|
+
return { error: "text is required" };
|
|
1038
|
+
}
|
|
1039
|
+
const outputFile = outputFileOf(params);
|
|
1040
|
+
const speechParams = {
|
|
1041
|
+
text,
|
|
1042
|
+
voice: params.voice,
|
|
1043
|
+
speed: params.speed,
|
|
1044
|
+
audioFormat: audioFormatFromOutputFile(outputFile) ?? "mp3"
|
|
1045
|
+
};
|
|
1046
|
+
const spec = {
|
|
1047
|
+
capability: "text_to_speech",
|
|
1048
|
+
m,
|
|
1049
|
+
type: "audio",
|
|
1050
|
+
namePrefix: "generated-speech",
|
|
1051
|
+
params: { ...speechParams }
|
|
1052
|
+
};
|
|
1053
|
+
const req = generationRequest(randomUUID(), params, spec);
|
|
1054
|
+
return runAudioGeneration(run.context, req, spec, params, (provider, signal) => speechAudio(run.context, provider, m, speechParams, signal, outputFile));
|
|
1020
1055
|
}
|
|
1021
1056
|
};
|
|
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
1057
|
const generateMusic = {
|
|
1032
1058
|
spec: generateMusicSpec,
|
|
1033
1059
|
impl: async (run, params) => {
|
|
1034
|
-
const context = run.context;
|
|
1035
1060
|
const m = parseModelArgs(params);
|
|
1036
|
-
if ("error" in m)
|
|
1061
|
+
if ("error" in m) {
|
|
1037
1062
|
return m;
|
|
1038
|
-
|
|
1039
|
-
|
|
1063
|
+
}
|
|
1064
|
+
const prompt = params.prompt;
|
|
1065
|
+
if (!isNonEmptyString(prompt)) {
|
|
1040
1066
|
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
1067
|
}
|
|
1046
|
-
const outputFile =
|
|
1047
|
-
? params["output_file"]
|
|
1048
|
-
: undefined;
|
|
1049
|
-
const desiredFormat = audioFormatFromOutputFile(outputFile) ?? "mp3";
|
|
1050
|
-
const generationId = randomUUID();
|
|
1068
|
+
const outputFile = outputFileOf(params);
|
|
1051
1069
|
const musicParams = {
|
|
1052
1070
|
prompt,
|
|
1053
|
-
lyrics: params
|
|
1071
|
+
lyrics: params.lyrics,
|
|
1054
1072
|
duration_seconds: aliased(params, "duration_seconds", "durationSeconds", "duration"),
|
|
1055
|
-
audioFormat:
|
|
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) } : {}
|
|
1073
|
+
audioFormat: audioFormatFromOutputFile(outputFile) ?? "mp3"
|
|
1065
1074
|
};
|
|
1066
1075
|
const spec = {
|
|
1067
1076
|
capability: "text_to_music",
|
|
@@ -1070,45 +1079,31 @@ const generateMusic = {
|
|
|
1070
1079
|
namePrefix: "generated-music",
|
|
1071
1080
|
params: musicParams
|
|
1072
1081
|
};
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
+
const req = generationRequest(randomUUID(), params, spec);
|
|
1083
|
+
return runAudioGeneration(run.context, req, spec, params, async (provider, signal) => {
|
|
1084
|
+
signal.throwIfAborted();
|
|
1085
|
+
const encoded = provider
|
|
1086
|
+
? await provider.textToMusic({
|
|
1087
|
+
prompt,
|
|
1088
|
+
model: { id: m.model, name: m.model, provider: m.provider },
|
|
1089
|
+
lyrics: isString(params.lyrics) ? params.lyrics : undefined,
|
|
1090
|
+
durationSeconds: typeof musicParams.duration_seconds === "number"
|
|
1091
|
+
? musicParams.duration_seconds
|
|
1092
|
+
: undefined,
|
|
1093
|
+
audioFormat: musicParams.audioFormat,
|
|
1094
|
+
signal
|
|
1095
|
+
})
|
|
1096
|
+
: await run.context.textToMusic(req);
|
|
1097
|
+
signal.throwIfAborted();
|
|
1082
1098
|
if (!encoded?.data || encoded.data.length === 0) {
|
|
1083
|
-
|
|
1084
|
-
error: "Provider returned no audio data",
|
|
1085
|
-
generation_id: generationId
|
|
1086
|
-
};
|
|
1099
|
+
throw new Error("Provider returned no audio data");
|
|
1087
1100
|
}
|
|
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
1101
|
return {
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
generation_id: generationId,
|
|
1103
|
-
...persisted
|
|
1102
|
+
data: encoded.data,
|
|
1103
|
+
mimeType: encoded.mimeType ?? "audio/mpeg",
|
|
1104
|
+
outputFile
|
|
1104
1105
|
};
|
|
1105
|
-
}
|
|
1106
|
-
catch (e) {
|
|
1107
|
-
return {
|
|
1108
|
-
...predictionError("text_to_music", m, e),
|
|
1109
|
-
generation_id: generationId
|
|
1110
|
-
};
|
|
1111
|
-
}
|
|
1106
|
+
});
|
|
1112
1107
|
}
|
|
1113
1108
|
};
|
|
1114
1109
|
const transcribeAudio = {
|
|
@@ -1244,7 +1239,7 @@ function messageText(message) {
|
|
|
1244
1239
|
}
|
|
1245
1240
|
return "";
|
|
1246
1241
|
}
|
|
1247
|
-
async function judgeCall(context, m, content, maxTokens = JUDGE_MAX_TOKENS) {
|
|
1242
|
+
async function judgeCall(context, m, content, maxTokens = JUDGE_MAX_TOKENS, requiredImages) {
|
|
1248
1243
|
const result = (await context.runProviderPrediction({
|
|
1249
1244
|
provider: m.provider,
|
|
1250
1245
|
capability: "generate_message",
|
|
@@ -1252,7 +1247,10 @@ async function judgeCall(context, m, content, maxTokens = JUDGE_MAX_TOKENS) {
|
|
|
1252
1247
|
params: {
|
|
1253
1248
|
messages: [{ role: "user", content }],
|
|
1254
1249
|
max_tokens: maxTokens,
|
|
1255
|
-
temperature: 0
|
|
1250
|
+
temperature: 0,
|
|
1251
|
+
strict_image_evidence: content.some((part) => part.type === "image_url") ||
|
|
1252
|
+
Boolean(requiredImages?.length),
|
|
1253
|
+
required_images: requiredImages?.map(normalizeMediaSource)
|
|
1256
1254
|
}
|
|
1257
1255
|
}));
|
|
1258
1256
|
return messageText(result);
|
|
@@ -1403,11 +1401,7 @@ const compareImages = {
|
|
|
1403
1401
|
`\n\nRespond with JSON only: {"winner": 1 | 2, "reason": "one sentence"}`;
|
|
1404
1402
|
const judgePair = async (a, b) => {
|
|
1405
1403
|
const call = async (first, second) => {
|
|
1406
|
-
const text = await judgeCall(context, m, [
|
|
1407
|
-
textPart(prompt),
|
|
1408
|
-
imagePart(first),
|
|
1409
|
-
imagePart(second)
|
|
1410
|
-
]);
|
|
1404
|
+
const text = await judgeCall(context, m, [textPart(prompt), imagePart(first), imagePart(second)], JUDGE_MAX_TOKENS, images.map(String));
|
|
1411
1405
|
const verdict = parsePairVerdict(text);
|
|
1412
1406
|
if (!verdict) {
|
|
1413
1407
|
throw new Error(`Judge did not return parseable JSON: ${text.slice(0, 200)}`);
|
|
@@ -1502,7 +1496,7 @@ const scoreImageAdherence = {
|
|
|
1502
1496
|
` visually checkable.` +
|
|
1503
1497
|
`\n\nBrief:\n${brief}` +
|
|
1504
1498
|
`\n\nRespond with JSON only: {"questions": ["..."]}`)
|
|
1505
|
-
]);
|
|
1499
|
+
], JUDGE_MAX_TOKENS, [image]);
|
|
1506
1500
|
const parsed = extractJSON(decomposeText);
|
|
1507
1501
|
const list = isRecord(parsed) ? parsed["questions"] : parsed;
|
|
1508
1502
|
questions = Array.isArray(list) ? list.map(String).filter(Boolean) : [];
|
|
@@ -1513,36 +1507,82 @@ const scoreImageAdherence = {
|
|
|
1513
1507
|
}
|
|
1514
1508
|
}
|
|
1515
1509
|
questions = questions.slice(0, MAX_ADHERENCE_QUESTIONS);
|
|
1510
|
+
const checks = questions.map((question, i) => ({
|
|
1511
|
+
id: `q${i + 1}`,
|
|
1512
|
+
question
|
|
1513
|
+
}));
|
|
1516
1514
|
const answerText = await judgeCall(context, m, [
|
|
1517
1515
|
textPart(`Answer each question about the image with a strict yes or no. "yes" only if` +
|
|
1518
1516
|
` the image clearly satisfies it; when unsure, answer "no" and say why in the note.` +
|
|
1519
|
-
`\n\nQuestions:\n${
|
|
1517
|
+
`\n\nQuestions:\n${checks.map((q) => `${q.id}: ${q.question}`).join("\n")}` +
|
|
1520
1518
|
`\n\nRespond with JSON only:` +
|
|
1521
|
-
`\n{"answers": [{"question": "...", "answer": "yes" | "no", "note": "..."}]}`),
|
|
1519
|
+
`\n{"answers": [{"id": "q1", "question": "...", "answer": "yes" | "no", "note": "..."}]}`),
|
|
1522
1520
|
imagePart(image)
|
|
1523
1521
|
]);
|
|
1524
1522
|
const parsed = extractJSON(answerText);
|
|
1525
1523
|
const rawAnswers = isRecord(parsed) ? parsed["answers"] : null;
|
|
1526
1524
|
if (!Array.isArray(rawAnswers) || rawAnswers.length === 0) {
|
|
1527
1525
|
return {
|
|
1528
|
-
error: `Judge did not return parseable answers: ${answerText.slice(0, 300)}
|
|
1526
|
+
error: `Judge did not return parseable answers: ${answerText.slice(0, 300)}`,
|
|
1527
|
+
evidence_status: "invalid",
|
|
1528
|
+
total: checks.length,
|
|
1529
|
+
missing_ids: checks.map((check) => check.id)
|
|
1529
1530
|
};
|
|
1530
1531
|
}
|
|
1531
|
-
const
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1532
|
+
const byId = new Map();
|
|
1533
|
+
const invalid = [];
|
|
1534
|
+
for (const raw of rawAnswers) {
|
|
1535
|
+
if (!isRecord(raw)) {
|
|
1536
|
+
invalid.push("answer must be an object");
|
|
1537
|
+
continue;
|
|
1538
|
+
}
|
|
1539
|
+
const id = String(raw["id"] ?? "");
|
|
1540
|
+
const check = checks.find((c) => c.id === id);
|
|
1541
|
+
if (!check || raw["question"] !== check.question) {
|
|
1542
|
+
invalid.push(`unrequested or substituted check: ${id}`);
|
|
1543
|
+
continue;
|
|
1544
|
+
}
|
|
1545
|
+
if (byId.has(id)) {
|
|
1546
|
+
invalid.push(`duplicate check: ${id}`);
|
|
1547
|
+
continue;
|
|
1548
|
+
}
|
|
1549
|
+
if (raw["answer"] !== "yes" && raw["answer"] !== "no") {
|
|
1550
|
+
invalid.push(`invalid answer: ${id}`);
|
|
1551
|
+
continue;
|
|
1552
|
+
}
|
|
1553
|
+
byId.set(id, {
|
|
1554
|
+
id,
|
|
1555
|
+
question: check.question,
|
|
1556
|
+
answer: raw["answer"],
|
|
1557
|
+
note: String(raw["note"] ?? "")
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
const missingIds = checks.filter((c) => !byId.has(c.id)).map((c) => c.id);
|
|
1561
|
+
if (invalid.length || missingIds.length) {
|
|
1562
|
+
return {
|
|
1563
|
+
error: "Judge returned invalid or incomplete adherence evidence",
|
|
1564
|
+
evidence_status: "invalid",
|
|
1565
|
+
total: checks.length,
|
|
1566
|
+
missing_ids: missingIds,
|
|
1567
|
+
invalid
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
const answers = [];
|
|
1571
|
+
for (const check of checks) {
|
|
1572
|
+
const answer = byId.get(check.id);
|
|
1573
|
+
if (answer) {
|
|
1574
|
+
answers.push(answer);
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1538
1577
|
const passed = answers.filter((a) => a.answer === "yes").length;
|
|
1539
1578
|
return {
|
|
1540
1579
|
type: "adherence",
|
|
1580
|
+
evidence_status: "complete",
|
|
1541
1581
|
provider: m.provider,
|
|
1542
1582
|
model: m.model,
|
|
1543
|
-
score:
|
|
1583
|
+
score: passed / checks.length,
|
|
1544
1584
|
passed,
|
|
1545
|
-
total:
|
|
1585
|
+
total: checks.length,
|
|
1546
1586
|
failed: answers.filter((a) => a.answer === "no"),
|
|
1547
1587
|
answers
|
|
1548
1588
|
};
|
|
@@ -1810,7 +1850,8 @@ async function stageInputs(context, workspace, cwd, raw) {
|
|
|
1810
1850
|
const localAssetLimit = workspace.localDir
|
|
1811
1851
|
? getMaxLocalUploadBytes()
|
|
1812
1852
|
: undefined;
|
|
1813
|
-
const hasLocalAsset = localAssetLimit !== undefined &&
|
|
1853
|
+
const hasLocalAsset = localAssetLimit !== undefined &&
|
|
1854
|
+
entries.some(([, ref]) => isNonBlankString(ref) && ref.trim().startsWith("asset://"));
|
|
1814
1855
|
const totalLimit = hasLocalAsset
|
|
1815
1856
|
? Math.max(MAX_STAGED_TOTAL_BYTES, localAssetLimit ?? 0)
|
|
1816
1857
|
: MAX_STAGED_TOTAL_BYTES;
|