| import fs from "node:fs/promises"; |
| import path from "node:path"; |
| import { afterEach, describe, expect, it } from "vitest"; |
| import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js"; |
| import { resolveRuntimeWorkerArgv, resolveRuntimeWorkerUrl } from "../infra/runtime-worker-url.js"; |
| import { createWhisperExecutable } from "../media-understanding/local-audio.test-support.js"; |
| import { createSafeAudioFixtureBuffer } from "../media-understanding/runner.test-utils.js"; |
| import { cliRecoveryEntrypoints } from "./cli-entrypoint.test-support.js"; |
| import { runCliProcessChild } from "./cli-process-child.test-helpers.js"; |
|
|
| const tempDirs = useAutoCleanupTempDirTracker(afterEach); |
|
|
| |
| describe.skipIf(process.platform === "win32")("infer local audio executable selection", () => { |
| it.each([ |
| { name: "a literal home-relative PATH", homeRelative: true, decoy: false }, |
| { name: "a home-relative PATH before a later decoy", homeRelative: true, decoy: true }, |
| { name: "an absolute PATH", homeRelative: false, decoy: false }, |
| ])("transcribes with the discovered executable from $name", async ({ homeRelative, decoy }) => { |
| const root = tempDirs.make("openclaw-infer-local-audio-"); |
| const binDir = path.join(root, "qa-stt-bin"); |
| const decoyDir = path.join(root, "decoy-bin"); |
| const tmp = path.join(root, "tmp"); |
| const workspace = path.join(root, "workspace"); |
| await Promise.all([binDir, decoyDir, tmp, workspace].map((dir) => fs.mkdir(dir))); |
| const transcript = "preferred synthetic transcript"; |
| await createWhisperExecutable(binDir, transcript); |
| if (decoy) { |
| await createWhisperExecutable(decoyDir, "wrong executable transcript"); |
| } |
| const mediaPath = path.join(root, "input.wav"); |
| await fs.writeFile(mediaPath, createSafeAudioFixtureBuffer(2048, 0x52)); |
| const configPath = path.join(root, "openclaw.json"); |
| await fs.writeFile( |
| configPath, |
| JSON.stringify({ |
| agents: { defaults: { workspace }, entries: { main: {} } }, |
| plugins: { enabled: false }, |
| tools: { media: { audio: { enabled: true } } }, |
| logging: { level: "silent", consoleLevel: "silent" }, |
| }), |
| ); |
| const searchPath = [homeRelative ? "~/qa-stt-bin" : binDir, ...(decoy ? [decoyDir] : [])]; |
| const result = await runCliProcessChild({ |
| nodeArgs: [ |
| ...resolveRuntimeWorkerArgv(resolveRuntimeWorkerUrl(cliRecoveryEntrypoints.cli)), |
| "infer", |
| "audio", |
| "transcribe", |
| "--file", |
| mediaPath, |
| "--json", |
| ], |
| cwd: root, |
| env: { |
| PATH: searchPath.join(path.delimiter), |
| ESBUILD_WORKER_THREADS: process.env.ESBUILD_WORKER_THREADS, |
| HOME: root, |
| USERPROFILE: root, |
| TMPDIR: tmp, |
| TMP: tmp, |
| TEMP: tmp, |
| OPENCLAW_CONFIG_PATH: configPath, |
| OPENCLAW_STATE_DIR: path.join(root, "state"), |
| OPENCLAW_DISABLE_BUNDLED_PLUGINS: "1", |
| |
| OPENCLAW_PATH_BOOTSTRAPPED: "1", |
| OPENCLAW_NO_RESPAWN: "1", |
| NODE_DISABLE_COMPILE_CACHE: "1", |
| NO_COLOR: "1", |
| }, |
| }); |
| expect(result.signal, result.stderr).toBeNull(); |
| expect(result.code, result.stderr).toBe(0); |
| expect(JSON.parse(result.stdout)).toMatchObject({ |
| ok: true, |
| capability: "audio.transcribe", |
| transport: "local", |
| provider: "whisper", |
| outputs: [{ path: mediaPath, text: transcript, kind: "audio.transcription" }], |
| }); |
| }); |
| }); |
|
|