@qvac/sdk 0.20.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +76 -13
- package/README.md +39 -5
- package/dist/examples/advisory-model-fit.d.ts +17 -16
- package/dist/examples/advisory-model-fit.js +18 -18
- package/dist/examples/asr/parakeet-indic-conformer-filesystem.js +3 -3
- package/dist/examples/asr/parakeet-unified-coreml.d.ts +2 -0
- package/dist/examples/asr/parakeet-unified-coreml.js +113 -0
- package/dist/examples/assess-model-fit.js +9 -4
- package/dist/examples/model-fit-ui/server.js +5 -2
- package/dist/examples/rpc-inference.d.ts +2 -0
- package/dist/examples/rpc-inference.js +51 -0
- package/dist/examples/rpc-server.d.ts +2 -0
- package/dist/examples/rpc-server.js +32 -0
- package/dist/examples/tools/llamacpp-deferred-tools.d.ts +2 -0
- package/dist/examples/tools/llamacpp-deferred-tools.js +77 -0
- package/dist/examples/tts/audio8.js +4 -0
- package/dist/examples/tts/moss-dialogue.d.ts +2 -0
- package/dist/examples/tts/moss-dialogue.js +63 -0
- package/dist/examples/tts/moss.d.ts +2 -0
- package/dist/examples/tts/moss.js +71 -0
- package/dist/scripts/contract/build-contract.d.ts +2 -1
- package/dist/scripts/contract/build-contract.js +4 -1
- package/dist/scripts/contract/build-numeric-constants.d.ts +15 -0
- package/dist/scripts/contract/build-numeric-constants.js +13 -0
- package/dist/scripts/contract/method-shapes.d.ts +3 -0
- package/dist/scripts/contract/method-shapes.js +3 -0
- package/dist/scripts/enforce-inference-versions.d.ts +18 -0
- package/dist/scripts/enforce-inference-versions.js +158 -0
- package/dist/scripts/generate-bare-kit-runtimes.d.ts +2 -0
- package/dist/scripts/generate-bare-kit-runtimes.js +106 -0
- package/dist/src/client/api/assess-model-fit.d.ts +5 -4
- package/dist/src/client/api/assess-model-fit.js +24 -7
- package/dist/src/client/api/bci-transcribe.d.ts +4 -1
- package/dist/src/client/api/get-system-resources.d.ts +8 -0
- package/dist/src/client/api/get-system-resources.js +8 -0
- package/dist/src/client/api/index.d.ts +1 -0
- package/dist/src/client/api/index.js +1 -0
- package/dist/src/client/api/rpc-server.d.ts +20 -0
- package/dist/src/client/api/rpc-server.js +45 -0
- package/dist/src/client/api/text-to-speech.d.ts +9 -0
- package/dist/src/client/api/text-to-speech.js +9 -0
- package/dist/src/client/api/transcribe.d.ts +21 -15
- package/dist/src/client/api/transcribe.js +65 -20
- package/dist/src/client/rpc/rpc-error.js +11 -7
- package/dist/src/commands/bundle/entry-gen.d.ts +2 -2
- package/dist/src/commands/bundle/entry-gen.js +8 -4
- package/dist/src/commands/bundle/index.d.ts +20 -0
- package/dist/src/commands/bundle/index.js +88 -12
- package/dist/src/commands/bundle/plugins.js +1 -1
- package/dist/src/commands/command-logger.d.ts +6 -0
- package/dist/src/commands/command-logger.js +12 -0
- package/dist/src/commands/host-prebuilds/index.d.ts +71 -0
- package/dist/src/commands/host-prebuilds/index.js +227 -0
- package/dist/src/commands/host-prebuilds/package-manager.d.ts +54 -0
- package/dist/src/commands/host-prebuilds/package-manager.js +278 -0
- package/dist/src/commands/index.d.ts +10 -1
- package/dist/src/commands/index.js +6 -0
- package/dist/src/commands/verify/abi.d.ts +22 -2
- package/dist/src/commands/verify/abi.js +49 -27
- package/dist/src/commands/verify/addon-source.d.ts +22 -0
- package/dist/src/commands/verify/addon-source.js +69 -3
- package/dist/src/commands/verify/bare-kit-runtime.d.ts +38 -0
- package/dist/src/commands/verify/bare-kit-runtime.js +201 -0
- package/dist/src/commands/verify/bare-kit-runtimes.d.ts +12 -0
- package/dist/src/commands/verify/bare-kit-runtimes.js +108 -0
- package/dist/src/commands/verify/bundle-source.js +16 -15
- package/dist/src/commands/verify/engines-advice.d.ts +73 -0
- package/dist/src/commands/verify/engines-advice.js +271 -0
- package/dist/src/commands/verify/index.d.ts +22 -0
- package/dist/src/commands/verify/index.js +151 -13
- package/dist/src/commands/verify/node-modules-source.js +43 -39
- package/dist/src/commands/verify/prebuilds.d.ts +19 -0
- package/dist/src/commands/verify/prebuilds.js +52 -13
- package/dist/src/expo/plugins/index.d.ts +2 -0
- package/dist/src/expo/plugins/withMobileBundle.d.ts +15 -5
- package/dist/src/expo/plugins/withMobileBundle.js +68 -42
- package/dist/src/expo/plugins/withQvacSDK.d.ts +7 -1
- package/dist/src/expo/plugins/withQvacSDK.js +6 -3
- package/dist/src/index.d.ts +5 -2
- package/dist/src/index.js +4 -2
- package/dist/src/schemas/sdk-errors-client.d.ts +2 -0
- package/dist/src/schemas/sdk-errors-client.js +16 -0
- package/dist/src/schemas/sdk-errors-server.d.ts +1 -0
- package/dist/src/schemas/sdk-errors-server.js +5 -0
- package/dist/src/utils/errors-client.d.ts +15 -0
- package/dist/src/utils/errors-client.js +26 -0
- package/dist/src/utils/errors-server.d.ts +1 -0
- package/dist/src/utils/errors-server.js +1 -0
- package/dist/src/utils/mcp-adapter.js +7 -1
- package/dist/src/utils/tool-helpers.d.ts +4 -0
- package/dist/src/utils/tool-helpers.js +2 -0
- package/dist/src/worker/ggml-rpc-server-provider.d.ts +2 -0
- package/dist/src/worker/ggml-rpc-server-provider.js +1 -0
- package/dist/src/worker/rpc-server-provider.d.ts +3 -0
- package/dist/src/worker/rpc-server-provider.js +1 -0
- package/package.json +30 -25
- package/dist/scripts/enforce-inference-peer-dependencies.d.ts +0 -2
- package/dist/scripts/enforce-inference-peer-dependencies.js +0 -39
- package/dist/src/deprecate.d.ts +0 -2
- package/dist/src/deprecate.js +0 -9
- package/dist/src/worker/legacy-worker-entry.d.ts +0 -2
- package/dist/src/worker/legacy-worker-entry.js +0 -3
- package/dist/src/worker/worker-core.d.ts +0 -7
- package/dist/src/worker/worker-core.js +0 -8
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { promises as fsp } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import semver from 'semver';
|
|
5
|
+
import { fetchBareKitVersionFromGitHub, fetchBareVersionFromGitHub, fetchText, REACT_NATIVE_BARE_KIT } from '../src/commands/verify/bare-kit-runtime.js';
|
|
6
|
+
import { BARE_KIT_BARE_VERSIONS, REACT_NATIVE_BARE_KIT_RUNTIMES } from '../src/commands/verify/bare-kit-runtimes.js';
|
|
7
|
+
const CONCURRENCY = 8;
|
|
8
|
+
const OUTPUT_PATH = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'src', 'commands', 'verify', 'bare-kit-runtimes.ts');
|
|
9
|
+
async function listPublishedVersions() {
|
|
10
|
+
const metadata = JSON.parse(await fetchText(`https://registry.npmjs.org/${REACT_NATIVE_BARE_KIT}`));
|
|
11
|
+
return Object.keys(metadata.versions);
|
|
12
|
+
}
|
|
13
|
+
async function listBareKitTags() {
|
|
14
|
+
const tags = JSON.parse(await fetchText('https://api.github.com/repos/holepunchto/bare-kit/tags?per_page=100'));
|
|
15
|
+
return tags.map((tag) => tag.name.replace(/^v/, ''));
|
|
16
|
+
}
|
|
17
|
+
function latest(versions) {
|
|
18
|
+
const valid = versions.filter((version) => semver.valid(version) !== null);
|
|
19
|
+
return valid.length === 0 ? null : valid.sort(semver.rcompare)[0];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Releases newer than the newest one already in the table, oldest first.
|
|
23
|
+
* Everything at or below it was probed on an earlier run, including the old
|
|
24
|
+
* react-native-bare-kit releases that have no CMakeLists.txt to parse.
|
|
25
|
+
*/
|
|
26
|
+
function newerThan(versions, lastKnown) {
|
|
27
|
+
return versions
|
|
28
|
+
.filter((version) => semver.valid(version) !== null)
|
|
29
|
+
.filter((version) => lastKnown === null || semver.gt(version, lastKnown))
|
|
30
|
+
.sort(semver.compare);
|
|
31
|
+
}
|
|
32
|
+
async function mapConcurrent(items, fn) {
|
|
33
|
+
const results = new Array(items.length);
|
|
34
|
+
let next = 0;
|
|
35
|
+
async function worker() {
|
|
36
|
+
while (next < items.length) {
|
|
37
|
+
const index = next++;
|
|
38
|
+
results[index] = await fn(items[index]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
await Promise.all(Array.from({ length: CONCURRENCY }, worker));
|
|
42
|
+
return results;
|
|
43
|
+
}
|
|
44
|
+
async function tryFetch(fn) {
|
|
45
|
+
try {
|
|
46
|
+
return await fn();
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function sortedEntries(record) {
|
|
53
|
+
return Object.entries(record).sort(([a], [b]) => semver.compare(a, b));
|
|
54
|
+
}
|
|
55
|
+
function render(runtimes, bareByBareKit) {
|
|
56
|
+
const lines = [
|
|
57
|
+
'// Generated by scripts/generate-bare-kit-runtimes.ts. Do not edit by hand.',
|
|
58
|
+
'',
|
|
59
|
+
'export interface BareKitRuntime {',
|
|
60
|
+
' bareKit: string',
|
|
61
|
+
' bare: string',
|
|
62
|
+
'}',
|
|
63
|
+
'',
|
|
64
|
+
'/**',
|
|
65
|
+
' * react-native-bare-kit releases whose CMakeLists.txt names the bare-kit',
|
|
66
|
+
' * prebuilds it ships. Older releases carry no such reference.',
|
|
67
|
+
' */',
|
|
68
|
+
'export const REACT_NATIVE_BARE_KIT_RUNTIMES: Record<string, BareKitRuntime> = {'
|
|
69
|
+
];
|
|
70
|
+
lines.push(...entryLines(sortedEntries(runtimes).map(([version, runtime]) => `'${version}': { bareKit: '${runtime.bareKit}', bare: '${runtime.bare}' }`)));
|
|
71
|
+
lines.push('}', '', '/** Bare version each bare-kit release is built against. */');
|
|
72
|
+
lines.push('export const BARE_KIT_BARE_VERSIONS: Record<string, string> = {');
|
|
73
|
+
lines.push(...entryLines(sortedEntries(bareByBareKit).map(([bareKit, bare]) => `'${bareKit}': '${bare}'`)));
|
|
74
|
+
lines.push('}', '');
|
|
75
|
+
return lines.join('\n');
|
|
76
|
+
}
|
|
77
|
+
/** Object entries in the repo's Prettier style: no trailing comma. */
|
|
78
|
+
function entryLines(entries) {
|
|
79
|
+
return entries.map((entry, index) => ` ${entry}${index === entries.length - 1 ? '' : ','}`);
|
|
80
|
+
}
|
|
81
|
+
async function main() {
|
|
82
|
+
const full = process.argv.includes('--full');
|
|
83
|
+
const bareByBareKit = full ? {} : { ...BARE_KIT_BARE_VERSIONS };
|
|
84
|
+
const runtimes = full ? {} : { ...REACT_NATIVE_BARE_KIT_RUNTIMES };
|
|
85
|
+
const bareKitTags = newerThan(await listBareKitTags(), latest(Object.keys(bareByBareKit)));
|
|
86
|
+
console.log(`Resolving ${bareKitTags.length} new bare-kit releases...`);
|
|
87
|
+
const bareVersions = await mapConcurrent(bareKitTags, (bareKit) => tryFetch(() => fetchBareVersionFromGitHub(bareKit)));
|
|
88
|
+
bareKitTags.forEach((bareKit, index) => {
|
|
89
|
+
const bare = bareVersions[index];
|
|
90
|
+
if (bare)
|
|
91
|
+
bareByBareKit[bareKit] = bare;
|
|
92
|
+
});
|
|
93
|
+
const versions = newerThan(await listPublishedVersions(), latest(Object.keys(runtimes)));
|
|
94
|
+
console.log(`Resolving ${versions.length} new ${REACT_NATIVE_BARE_KIT} releases...`);
|
|
95
|
+
const bareKitByVersion = await mapConcurrent(versions, (version) => tryFetch(() => fetchBareKitVersionFromGitHub(version)));
|
|
96
|
+
versions.forEach((version, index) => {
|
|
97
|
+
const bareKit = bareKitByVersion[index];
|
|
98
|
+
const bare = bareKit ? bareByBareKit[bareKit] : undefined;
|
|
99
|
+
if (bareKit && bare)
|
|
100
|
+
runtimes[version] = { bareKit, bare };
|
|
101
|
+
});
|
|
102
|
+
await fsp.writeFile(OUTPUT_PATH, render(runtimes, bareByBareKit));
|
|
103
|
+
console.log(`Wrote ${Object.keys(runtimes).length} ${REACT_NATIVE_BARE_KIT} and ` +
|
|
104
|
+
`${Object.keys(bareByBareKit).length} bare-kit entries to ${OUTPUT_PATH}`);
|
|
105
|
+
}
|
|
106
|
+
await main();
|
|
@@ -9,11 +9,12 @@ import { type AssessModelFitInput, type AssessModelFitResult } from '@qvac/infer
|
|
|
9
9
|
* should treat it as "cannot say", not "no".
|
|
10
10
|
*
|
|
11
11
|
* For a single candidate it fetches the registry's weightless description of
|
|
12
|
-
*
|
|
13
|
-
* fitter against
|
|
14
|
-
* unavailable, and for a set of candidates, the calibrated
|
|
12
|
+
* every source that load names — tens of KB each, never the weights — and runs
|
|
13
|
+
* the engine's own fitter against them, reported as `native-fit` evidence.
|
|
14
|
+
* Where that is unavailable, and for a set of candidates, the calibrated
|
|
15
|
+
* estimate stands.
|
|
15
16
|
*
|
|
16
|
-
* @param input -
|
|
17
|
+
* @param input - Loads to assess in `loadModel`'s own parameters, the declared
|
|
17
18
|
* execution mode, and the headroom policy.
|
|
18
19
|
* @returns Per-model and combined verdicts, with the budget and bounds they came
|
|
19
20
|
* from, plus every assumption that was made.
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import { assessModelFitInputSchema } from '@qvac/inference/surface';
|
|
1
|
+
import { assessModelFitInputSchema, inferModelTypeFromModelSrc } from '@qvac/inference/surface';
|
|
2
2
|
import { send } from '../rpc/rpc-client.js';
|
|
3
|
-
import { InvalidResponseError } from '../../utils/errors-client.js';
|
|
3
|
+
import { InvalidResponseError, ModelTypeRequiredError } from '../../utils/errors-client.js';
|
|
4
|
+
/**
|
|
5
|
+
* Names the engine a candidate omitted, from the source it carries.
|
|
6
|
+
*
|
|
7
|
+
* @throws {ModelTypeRequiredError} When the source names no engine either.
|
|
8
|
+
*/
|
|
9
|
+
function withModelType(candidate) {
|
|
10
|
+
if (candidate.modelType !== undefined)
|
|
11
|
+
return candidate;
|
|
12
|
+
const inferred = inferModelTypeFromModelSrc(candidate.modelSrc);
|
|
13
|
+
if (inferred === undefined)
|
|
14
|
+
throw new ModelTypeRequiredError();
|
|
15
|
+
return { ...candidate, modelType: inferred };
|
|
16
|
+
}
|
|
4
17
|
/**
|
|
5
18
|
* Assesses, before anything is downloaded, whether the given models are likely
|
|
6
19
|
* to fit in this device's memory.
|
|
@@ -11,17 +24,21 @@ import { InvalidResponseError } from '../../utils/errors-client.js';
|
|
|
11
24
|
* should treat it as "cannot say", not "no".
|
|
12
25
|
*
|
|
13
26
|
* For a single candidate it fetches the registry's weightless description of
|
|
14
|
-
*
|
|
15
|
-
* fitter against
|
|
16
|
-
* unavailable, and for a set of candidates, the calibrated
|
|
27
|
+
* every source that load names — tens of KB each, never the weights — and runs
|
|
28
|
+
* the engine's own fitter against them, reported as `native-fit` evidence.
|
|
29
|
+
* Where that is unavailable, and for a set of candidates, the calibrated
|
|
30
|
+
* estimate stands.
|
|
17
31
|
*
|
|
18
|
-
* @param input -
|
|
32
|
+
* @param input - Loads to assess in `loadModel`'s own parameters, the declared
|
|
19
33
|
* execution mode, and the headroom policy.
|
|
20
34
|
* @returns Per-model and combined verdicts, with the budget and bounds they came
|
|
21
35
|
* from, plus every assumption that was made.
|
|
22
36
|
*/
|
|
23
37
|
export async function assessModelFit(input) {
|
|
24
|
-
const parsed = assessModelFitInputSchema.parse(
|
|
38
|
+
const parsed = assessModelFitInputSchema.parse({
|
|
39
|
+
...input,
|
|
40
|
+
models: input.models.map(withModelType)
|
|
41
|
+
});
|
|
25
42
|
const request = { type: 'assessModelFit', ...parsed };
|
|
26
43
|
const response = await send(request);
|
|
27
44
|
if (response.type !== 'assessModelFit') {
|
|
@@ -37,7 +37,10 @@ export declare function bciTranscribe(params: BciTranscribeClientParams, options
|
|
|
37
37
|
* @param params.modelId - The loaded BCI model to use.
|
|
38
38
|
* @param params.metadata - When true, the session yields transcript segment
|
|
39
39
|
* objects (`{ text, startMs, endMs, append, id }`)
|
|
40
|
-
* instead of plain text.
|
|
40
|
+
* instead of plain text. With `emit: 'delta'`, each
|
|
41
|
+
* segment also carries `windowStartTimestep`: its
|
|
42
|
+
* timestamps are window-local, and this maps them
|
|
43
|
+
* onto the stream timeline.
|
|
41
44
|
* @param params.windowTimesteps - Decode window size in timesteps.
|
|
42
45
|
* @param params.hopTimesteps - How far the window advances between decodes.
|
|
43
46
|
* @param params.emit - `'delta'` (default) yields only the newly-discovered
|
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
import { type GetSystemResourcesInput, type SystemResources } from '@qvac/inference/surface';
|
|
2
|
+
/**
|
|
3
|
+
* Read the worker's system capabilities and optional resource sample.
|
|
4
|
+
*
|
|
5
|
+
* @param input - Optional settings; set `sample` to request a current resource sample.
|
|
6
|
+
* @returns System capabilities with availability information and a sample when provided by the worker.
|
|
7
|
+
* @throws {InvalidResponseError} If the worker returns a different response type.
|
|
8
|
+
* @throws {Error} If the RPC request fails.
|
|
9
|
+
*/
|
|
2
10
|
export declare function getSystemResources(input?: GetSystemResourcesInput): Promise<SystemResources>;
|
|
3
11
|
//# sourceMappingURL=get-system-resources.d.ts.map
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import {} from '@qvac/inference/surface';
|
|
2
2
|
import { send } from '../rpc/rpc-client.js';
|
|
3
3
|
import { InvalidResponseError } from '../../utils/errors-client.js';
|
|
4
|
+
/**
|
|
5
|
+
* Read the worker's system capabilities and optional resource sample.
|
|
6
|
+
*
|
|
7
|
+
* @param input - Optional settings; set `sample` to request a current resource sample.
|
|
8
|
+
* @returns System capabilities with availability information and a sample when provided by the worker.
|
|
9
|
+
* @throws {InvalidResponseError} If the worker returns a different response type.
|
|
10
|
+
* @throws {Error} If the RPC request fails.
|
|
11
|
+
*/
|
|
4
12
|
export async function getSystemResources(input) {
|
|
5
13
|
const request = {
|
|
6
14
|
type: 'getSystemResources',
|
|
@@ -37,4 +37,5 @@ export { vlaPreprocessImage, vlaPadState, VLA_DEFAULT_IMAGE_SIZE } from './vla-h
|
|
|
37
37
|
export { audioGen } from './audio-gen.js';
|
|
38
38
|
export { audioEdit } from './audio-edit.js';
|
|
39
39
|
export { audioUnderstand } from './audio-understand.js';
|
|
40
|
+
export { startRpcServer, stopRpcServer, discoverRpcServers } from './rpc-server.js';
|
|
40
41
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -37,3 +37,4 @@ export { vlaPreprocessImage, vlaPadState, VLA_DEFAULT_IMAGE_SIZE } from './vla-h
|
|
|
37
37
|
export { audioGen } from './audio-gen.js';
|
|
38
38
|
export { audioEdit } from './audio-edit.js';
|
|
39
39
|
export { audioUnderstand } from './audio-understand.js';
|
|
40
|
+
export { startRpcServer, stopRpcServer, discoverRpcServers } from './rpc-server.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type StartRpcServerOptions, type StopRpcServerOptions, type DiscoverRpcServersOptions, type RpcServerInfo, type RpcServerCandidate } from '@qvac/inference/surface';
|
|
2
|
+
/**
|
|
3
|
+
* Start a worker-owned native RPC server. Non-loopback binding and advertising require explicit opt-in.
|
|
4
|
+
* Cancel a pending start with its promise.requestId.
|
|
5
|
+
*/
|
|
6
|
+
export declare function startRpcServer(options?: StartRpcServerOptions): Promise<RpcServerInfo> & {
|
|
7
|
+
requestId: string;
|
|
8
|
+
};
|
|
9
|
+
/** Withdraw the announcement and await native stop. Bare stop has no deadline. */
|
|
10
|
+
export declare function stopRpcServer(options: StopRpcServerOptions): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Find private-network candidates with device inventories and server RDMA availability.
|
|
13
|
+
* RDMA availability is a server-side offer, not a guarantee of the negotiated transport.
|
|
14
|
+
* Use getRpcDeviceMap with the chosen endpoint registration order before loadModel.
|
|
15
|
+
* Cancel a pending search with its promise.requestId.
|
|
16
|
+
*/
|
|
17
|
+
export declare function discoverRpcServers(options: DiscoverRpcServersOptions): Promise<RpcServerCandidate[]> & {
|
|
18
|
+
requestId: string;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=rpc-server.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {} from '@qvac/inference/surface';
|
|
2
|
+
import { send } from '../rpc/rpc-client.js';
|
|
3
|
+
import { InvalidResponseError } from '../../utils/errors-client.js';
|
|
4
|
+
import { decoratePromise } from '../../utils/decorate-promise.js';
|
|
5
|
+
import { generateClientRequestId } from './client-request-id.js';
|
|
6
|
+
/**
|
|
7
|
+
* Start a worker-owned native RPC server. Non-loopback binding and advertising require explicit opt-in.
|
|
8
|
+
* Cancel a pending start with its promise.requestId.
|
|
9
|
+
*/
|
|
10
|
+
export function startRpcServer(options = {}) {
|
|
11
|
+
const requestId = generateClientRequestId();
|
|
12
|
+
return decoratePromise(runStartRpcServer(options, requestId), { requestId });
|
|
13
|
+
}
|
|
14
|
+
async function runStartRpcServer(options, requestId) {
|
|
15
|
+
const response = await send({ ...options, type: 'startRpcServer', requestId });
|
|
16
|
+
if (response.type !== 'startRpcServer')
|
|
17
|
+
throw new InvalidResponseError('startRpcServer');
|
|
18
|
+
return {
|
|
19
|
+
serverId: response.serverId,
|
|
20
|
+
url: response.url,
|
|
21
|
+
rdmaCapable: response.rdmaCapable
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** Withdraw the announcement and await native stop. Bare stop has no deadline. */
|
|
25
|
+
export async function stopRpcServer(options) {
|
|
26
|
+
const response = await send({ ...options, type: 'stopRpcServer' });
|
|
27
|
+
if (response.type !== 'stopRpcServer')
|
|
28
|
+
throw new InvalidResponseError('stopRpcServer');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Find private-network candidates with device inventories and server RDMA availability.
|
|
32
|
+
* RDMA availability is a server-side offer, not a guarantee of the negotiated transport.
|
|
33
|
+
* Use getRpcDeviceMap with the chosen endpoint registration order before loadModel.
|
|
34
|
+
* Cancel a pending search with its promise.requestId.
|
|
35
|
+
*/
|
|
36
|
+
export function discoverRpcServers(options) {
|
|
37
|
+
const requestId = generateClientRequestId();
|
|
38
|
+
return decoratePromise(runDiscoverRpcServers(options, requestId), { requestId });
|
|
39
|
+
}
|
|
40
|
+
async function runDiscoverRpcServers(options, requestId) {
|
|
41
|
+
const response = await send({ ...options, type: 'discoverRpcServers', requestId });
|
|
42
|
+
if (response.type !== 'discoverRpcServers')
|
|
43
|
+
throw new InvalidResponseError('discoverRpcServers');
|
|
44
|
+
return response.servers;
|
|
45
|
+
}
|
|
@@ -43,6 +43,15 @@ export declare class TtsMulticast {
|
|
|
43
43
|
* metadata with the audio. Multiple consumers can iterate the response
|
|
44
44
|
* independently via the underlying `TtsMulticast`.
|
|
45
45
|
*
|
|
46
|
+
* MOSS models stream natively rather than by sentence: under `stream: true`
|
|
47
|
+
* the whole text is one synthesis whose audio arrives every
|
|
48
|
+
* `streamChunkTokens` codec frames (in one piece when that is unset), so
|
|
49
|
+
* `durationTokens` and a MOSS-TTSD dialogue's reference transcripts apply to
|
|
50
|
+
* the text as a whole. `sentenceStream: true` still splits a single-speaker
|
|
51
|
+
* text; a dialogue rejects it. `sentenceStreamLocale` and
|
|
52
|
+
* `sentenceStreamMaxChunkScalars` configure that splitting, so a MOSS request
|
|
53
|
+
* rejects them unless it sets `sentenceStream: true`.
|
|
54
|
+
*
|
|
46
55
|
* `result.done` resolves to `true` when synthesis completes cleanly, `false`
|
|
47
56
|
* if the consumer breaks out before the terminal frame, or rejects on a
|
|
48
57
|
* pipeline error. Awaiting `done` is safe even when no stream is iterated.
|
|
@@ -202,6 +202,15 @@ function buildTextToSpeechStreamRequest(params, requestId) {
|
|
|
202
202
|
* metadata with the audio. Multiple consumers can iterate the response
|
|
203
203
|
* independently via the underlying `TtsMulticast`.
|
|
204
204
|
*
|
|
205
|
+
* MOSS models stream natively rather than by sentence: under `stream: true`
|
|
206
|
+
* the whole text is one synthesis whose audio arrives every
|
|
207
|
+
* `streamChunkTokens` codec frames (in one piece when that is unset), so
|
|
208
|
+
* `durationTokens` and a MOSS-TTSD dialogue's reference transcripts apply to
|
|
209
|
+
* the text as a whole. `sentenceStream: true` still splits a single-speaker
|
|
210
|
+
* text; a dialogue rejects it. `sentenceStreamLocale` and
|
|
211
|
+
* `sentenceStreamMaxChunkScalars` configure that splitting, so a MOSS request
|
|
212
|
+
* rejects them unless it sets `sentenceStream: true`.
|
|
213
|
+
*
|
|
205
214
|
* `result.done` resolves to `true` when synthesis completes cleanly, `false`
|
|
206
215
|
* if the consumer breaks out before the terminal frame, or rejects on a
|
|
207
216
|
* pipeline error. Awaiting `done` is safe even when no stream is iterated.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type TranscribeClientParams, type RPCOptions, type TranscribeSegment, type TranscribeStreamRequest, type TranscribeStreamClientParams, type TranscribeStreamSession, type TranscribeStreamMetadataSession, type TranscribeStreamConversationSession, type TranscribeStats } from '@qvac/inference/surface';
|
|
2
|
-
import { duplex } from '../rpc/rpc-client.js';
|
|
1
|
+
import { type TranscribeClientParams, type RPCOptions, type TranscribeSegment, type TranscribeStreamRequest, type TranscribeStreamClientParams, type TranscribeStreamSession, type TranscribeStreamMetadataSession, type TranscribeStreamConversationSession, type TranscribeStreamEvent, type TranscribeStats, type InferenceBackendDiagnostics } from '@qvac/inference/surface';
|
|
2
|
+
import { stream, duplex } from '../rpc/rpc-client.js';
|
|
3
3
|
type TranscribeDuplexFactory = (request: TranscribeStreamRequest, options?: RPCOptions) => ReturnType<typeof duplex>;
|
|
4
4
|
/**
|
|
5
5
|
* Transcribe audio and return the complete text. Accepts either a file
|
|
@@ -10,24 +10,27 @@ type TranscribeDuplexFactory = (request: TranscribeStreamRequest, options?: RPCO
|
|
|
10
10
|
* @param params.audioChunk - Audio input as either a file path (string) or audio buffer
|
|
11
11
|
* @param params.prompt - Optional initial prompt to guide the transcription
|
|
12
12
|
* @param params.metadata - When true, resolves to an array of transcript
|
|
13
|
-
* segments (`{ text, startMs, endMs, append, id }
|
|
14
|
-
*
|
|
13
|
+
* segments (`{ text, startMs, endMs, append, id }`,
|
|
14
|
+
* plus `isEndOfTurn` and `startsWord` on parakeet)
|
|
15
|
+
* instead of joined text.
|
|
15
16
|
* @param options - Optional RPC options including per-call profiling
|
|
16
17
|
* @returns A promise (decorated with `requestId`) resolving to the
|
|
17
18
|
* complete transcribed text, or — when `metadata` is true —
|
|
18
19
|
* the list of transcript segments in emission order. The
|
|
19
20
|
* `requestId` is reachable synchronously so callers can target
|
|
20
21
|
* this in-flight transcription with `cancel({ requestId })`
|
|
21
|
-
* before `await` resolves.
|
|
22
|
+
* before `await` resolves. `stats` resolves to the terminal engine
|
|
23
|
+
* statistics, including Parakeet's per-run Core ML usage.
|
|
22
24
|
*/
|
|
23
|
-
|
|
24
|
-
metadata: true;
|
|
25
|
-
}, options?: RPCOptions): Promise<TranscribeSegment[]> & {
|
|
26
|
-
requestId: string;
|
|
27
|
-
};
|
|
28
|
-
export declare function transcribe(params: TranscribeClientParams, options?: RPCOptions): Promise<string> & {
|
|
25
|
+
type TranscribeCall<T> = Promise<T> & {
|
|
29
26
|
requestId: string;
|
|
27
|
+
stats: Promise<TranscribeStats | undefined>;
|
|
30
28
|
};
|
|
29
|
+
export declare function transcribe(params: TranscribeClientParams & {
|
|
30
|
+
metadata: true;
|
|
31
|
+
}, options?: RPCOptions): TranscribeCall<TranscribeSegment[]>;
|
|
32
|
+
export declare function transcribe(params: TranscribeClientParams, options?: RPCOptions): TranscribeCall<string>;
|
|
33
|
+
export declare function createTranscribeCall(params: TranscribeClientParams, options?: RPCOptions, responseStream?: typeof stream): TranscribeCall<string | TranscribeSegment[]>;
|
|
31
34
|
/**
|
|
32
35
|
* @deprecated Pass audio via `transcribe()` instead. This overload will be
|
|
33
36
|
* removed in the next major version.
|
|
@@ -57,8 +60,9 @@ export declare function transcribeStream(params: TranscribeClientParams, options
|
|
|
57
60
|
* @param params.modelId - The loaded transcription model to use
|
|
58
61
|
* @param params.prompt - Optional initial prompt to guide transcription
|
|
59
62
|
* @param params.metadata - When true, the session yields transcript segment
|
|
60
|
-
* objects (`{ text, startMs, endMs, append, id }
|
|
61
|
-
*
|
|
63
|
+
* objects (`{ text, startMs, endMs, append, id }`,
|
|
64
|
+
* plus `isEndOfTurn` and `startsWord` on parakeet)
|
|
65
|
+
* instead of plain text.
|
|
62
66
|
* @param options - Optional RPC options including per-call profiling.
|
|
63
67
|
* @returns A session object: call `write(audioChunk)` with a `Uint8Array`
|
|
64
68
|
* (Node `Buffer` is a `Uint8Array` subtype) to feed audio,
|
|
@@ -81,13 +85,15 @@ export declare function transcribeStream(params: TranscribeStreamClientParams, o
|
|
|
81
85
|
* to surface strings or segments; `sessionName` is only used to label the
|
|
82
86
|
* "already iterated" error so callers see the correct session type.
|
|
83
87
|
*/
|
|
84
|
-
export declare function createTranscribeStreamSession<T>(params: TranscribeStreamClientParams, options: RPCOptions | undefined, process: (line: string,
|
|
88
|
+
export declare function createTranscribeStreamSession<T>(params: TranscribeStreamClientParams, options: RPCOptions | undefined, process: (line: string, onTerminal: (stats: TranscribeStats | undefined, diagnostics: InferenceBackendDiagnostics | undefined) => void) => T | undefined | null, sessionName: string, duplexFactory?: TranscribeDuplexFactory): Promise<{
|
|
85
89
|
stats: Promise<TranscribeStats | undefined>;
|
|
90
|
+
diagnostics: Promise<InferenceBackendDiagnostics | undefined>;
|
|
86
91
|
write(audioChunk: Uint8Array): void;
|
|
87
92
|
end(): void;
|
|
88
93
|
destroy(): void;
|
|
89
94
|
[Symbol.asyncIterator](): AsyncIterator<T>;
|
|
90
95
|
}>;
|
|
91
|
-
export declare function processLine(line: string,
|
|
96
|
+
export declare function processLine(line: string, onTerminal: (stats: TranscribeStats | undefined, diagnostics: InferenceBackendDiagnostics | undefined) => void): string | undefined | null;
|
|
97
|
+
export declare function processLineConversation(line: string, wantsMetadata: boolean, onTerminal: (stats: TranscribeStats | undefined, diagnostics: InferenceBackendDiagnostics | undefined) => void): TranscribeStreamEvent | undefined | null;
|
|
92
98
|
export {};
|
|
93
99
|
//# sourceMappingURL=transcribe.d.ts.map
|
|
@@ -18,26 +18,38 @@ function buildTranscribeRequest(params, requestId) {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
export function transcribe(params, options) {
|
|
21
|
+
return createTranscribeCall(params, options);
|
|
22
|
+
}
|
|
23
|
+
export function createTranscribeCall(params, options, responseStream = stream) {
|
|
21
24
|
// Client-generated id surfaced synchronously on the returned promise
|
|
22
25
|
// — same shape as `loadModel` / `downloadAsset` / `completion`. The
|
|
23
26
|
// CLI cancel bridge in `qvac serve` binds `req.on('close')` to
|
|
24
27
|
// `cancel({ requestId })` immediately after the call returns so a
|
|
25
28
|
// client disconnect aborts the in-flight transcription.
|
|
26
29
|
const requestId = generateClientRequestId();
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
let resolveStats = () => { };
|
|
31
|
+
let rejectStats = () => { };
|
|
32
|
+
const stats = new Promise((resolve, reject) => {
|
|
33
|
+
resolveStats = resolve;
|
|
34
|
+
rejectStats = reject;
|
|
35
|
+
});
|
|
36
|
+
stats.catch(() => { });
|
|
37
|
+
const inner = runTranscribe(params, requestId, options, resolveStats, responseStream);
|
|
38
|
+
inner.then(() => resolveStats(undefined), rejectStats);
|
|
39
|
+
return decoratePromise(inner, { requestId, stats });
|
|
29
40
|
}
|
|
30
|
-
async function runTranscribe(params, requestId, options) {
|
|
41
|
+
async function runTranscribe(params, requestId, options, onStats, responseStream) {
|
|
31
42
|
const request = buildTranscribeRequest(params, requestId);
|
|
32
43
|
if (params.metadata === true) {
|
|
33
44
|
const segments = [];
|
|
34
|
-
for await (const response of
|
|
45
|
+
for await (const response of responseStream(request, options)) {
|
|
35
46
|
if (response.type === 'transcribe') {
|
|
36
47
|
const parsed = transcribeResponseSchema.parse(response);
|
|
37
48
|
if (parsed.segment) {
|
|
38
49
|
segments.push(parsed.segment);
|
|
39
50
|
}
|
|
40
51
|
if (parsed.done) {
|
|
52
|
+
onStats(parsed.stats);
|
|
41
53
|
break;
|
|
42
54
|
}
|
|
43
55
|
}
|
|
@@ -45,13 +57,14 @@ async function runTranscribe(params, requestId, options) {
|
|
|
45
57
|
return segments;
|
|
46
58
|
}
|
|
47
59
|
let fullText = '';
|
|
48
|
-
for await (const response of
|
|
60
|
+
for await (const response of responseStream(request, options)) {
|
|
49
61
|
if (response.type === 'transcribe') {
|
|
50
62
|
const parsed = transcribeResponseSchema.parse(response);
|
|
51
63
|
if (parsed.text) {
|
|
52
64
|
fullText += parsed.text;
|
|
53
65
|
}
|
|
54
66
|
if (parsed.done) {
|
|
67
|
+
onStats(parsed.stats);
|
|
55
68
|
break;
|
|
56
69
|
}
|
|
57
70
|
}
|
|
@@ -144,16 +157,47 @@ export async function createTranscribeStreamSession(params, options, process, se
|
|
|
144
157
|
statsSettled = true;
|
|
145
158
|
rejectStatsPromise(error);
|
|
146
159
|
}
|
|
147
|
-
|
|
148
|
-
|
|
160
|
+
// Settled from the same terminal frame as `stats`, and on the same paths:
|
|
161
|
+
// resolved empty when the stream closes without one, rejected on error.
|
|
162
|
+
let diagnosticsSettled = false;
|
|
163
|
+
let resolveDiagnosticsPromise = () => { };
|
|
164
|
+
let rejectDiagnosticsPromise = () => { };
|
|
165
|
+
const diagnostics = new Promise((resolve, reject) => {
|
|
166
|
+
resolveDiagnosticsPromise = resolve;
|
|
167
|
+
rejectDiagnosticsPromise = reject;
|
|
168
|
+
});
|
|
169
|
+
diagnostics.catch(() => { });
|
|
170
|
+
function resolveDiagnostics(value) {
|
|
171
|
+
if (diagnosticsSettled)
|
|
172
|
+
return;
|
|
173
|
+
diagnosticsSettled = true;
|
|
174
|
+
resolveDiagnosticsPromise(value);
|
|
175
|
+
}
|
|
176
|
+
function rejectDiagnostics(error) {
|
|
177
|
+
if (diagnosticsSettled)
|
|
178
|
+
return;
|
|
179
|
+
diagnosticsSettled = true;
|
|
180
|
+
rejectDiagnosticsPromise(error);
|
|
181
|
+
}
|
|
182
|
+
function resolveTerminal(statsValue, diagnosticsValue) {
|
|
183
|
+
resolveStats(statsValue);
|
|
184
|
+
resolveDiagnostics(diagnosticsValue);
|
|
185
|
+
}
|
|
186
|
+
function resolveEmptyTerminal() {
|
|
187
|
+
resolveTerminal(undefined, undefined);
|
|
188
|
+
}
|
|
189
|
+
function rejectTerminal(error) {
|
|
190
|
+
rejectStats(error);
|
|
191
|
+
rejectDiagnostics(error);
|
|
149
192
|
}
|
|
150
193
|
function processResponse(line) {
|
|
151
|
-
return process(line,
|
|
194
|
+
return process(line, resolveTerminal);
|
|
152
195
|
}
|
|
153
|
-
const responses = parseLines(responseStream, processResponse,
|
|
196
|
+
const responses = parseLines(responseStream, processResponse, resolveEmptyTerminal, rejectTerminal);
|
|
154
197
|
let consumed = false;
|
|
155
198
|
return {
|
|
156
199
|
stats,
|
|
200
|
+
diagnostics,
|
|
157
201
|
write(audioChunk) {
|
|
158
202
|
requestStream.write(audioChunk);
|
|
159
203
|
},
|
|
@@ -161,7 +205,7 @@ export async function createTranscribeStreamSession(params, options, process, se
|
|
|
161
205
|
requestStream.end();
|
|
162
206
|
},
|
|
163
207
|
destroy() {
|
|
164
|
-
|
|
208
|
+
resolveEmptyTerminal();
|
|
165
209
|
requestStream.destroy();
|
|
166
210
|
responseStream.destroy();
|
|
167
211
|
},
|
|
@@ -182,7 +226,7 @@ function transcribeStreamDuplexMetadata(params, options) {
|
|
|
182
226
|
}
|
|
183
227
|
function transcribeStreamDuplexConversation(params, options) {
|
|
184
228
|
const wantsMetadata = params.metadata === true;
|
|
185
|
-
return createTranscribeStreamSession(params, options, (line,
|
|
229
|
+
return createTranscribeStreamSession(params, options, (line, onTerminal) => processLineConversation(line, wantsMetadata, onTerminal), 'TranscribeStreamConversationSession');
|
|
186
230
|
}
|
|
187
231
|
/**
|
|
188
232
|
* Line-delimited parser: reads newline-separated frames from a duplex
|
|
@@ -241,31 +285,32 @@ function parseResponseLine(line) {
|
|
|
241
285
|
* `undefined` for frames the caller should skip, or the value extracted from
|
|
242
286
|
* the frame.
|
|
243
287
|
*/
|
|
244
|
-
function processWith(line, extract,
|
|
288
|
+
function processWith(line, extract, onTerminal) {
|
|
245
289
|
const response = parseResponseLine(line);
|
|
246
290
|
if (response === null)
|
|
247
291
|
return undefined;
|
|
248
292
|
if (response.error)
|
|
249
293
|
throw new TranscriptionFailedError(response.error);
|
|
250
294
|
if (response.done) {
|
|
251
|
-
|
|
295
|
+
onTerminal(response.stats, response.diagnostics);
|
|
252
296
|
return null;
|
|
253
297
|
}
|
|
254
298
|
return extract(response);
|
|
255
299
|
}
|
|
256
|
-
export function processLine(line,
|
|
257
|
-
return processWith(line, (response) => (response.text?.trim() ? response.text : undefined),
|
|
300
|
+
export function processLine(line, onTerminal) {
|
|
301
|
+
return processWith(line, (response) => (response.text?.trim() ? response.text : undefined), onTerminal);
|
|
258
302
|
}
|
|
259
|
-
function processLineMetadata(line,
|
|
260
|
-
return processWith(line, (response) => response.segment,
|
|
303
|
+
function processLineMetadata(line, onTerminal) {
|
|
304
|
+
return processWith(line, (response) => response.segment, onTerminal);
|
|
261
305
|
}
|
|
262
|
-
function processLineConversation(line, wantsMetadata,
|
|
306
|
+
export function processLineConversation(line, wantsMetadata, onTerminal) {
|
|
263
307
|
return processWith(line, (response) => {
|
|
264
308
|
if (response.vad) {
|
|
265
309
|
return {
|
|
266
310
|
type: 'vad',
|
|
267
311
|
speaking: response.vad.speaking,
|
|
268
|
-
probability: response.vad.probability
|
|
312
|
+
probability: response.vad.probability,
|
|
313
|
+
...(response.vad.source && { source: response.vad.source })
|
|
269
314
|
};
|
|
270
315
|
}
|
|
271
316
|
if (response.endOfTurn) {
|
|
@@ -291,5 +336,5 @@ function processLineConversation(line, wantsMetadata, onStats) {
|
|
|
291
336
|
return { type: 'text', text: response.text };
|
|
292
337
|
}
|
|
293
338
|
return undefined;
|
|
294
|
-
},
|
|
339
|
+
}, onTerminal);
|
|
295
340
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ContextOverflowError, RequestIdConflictError, RequestNotFoundError, RequestRejectedByPolicyError, TranslationFailedError } from '../../utils/errors-server.js';
|
|
1
|
+
import { RpcServerOperationError, InferenceCancelledError, ContextOverflowError, RequestIdConflictError, RequestNotFoundError, RequestRejectedByPolicyError, TranslationFailedError } from '../../utils/errors-server.js';
|
|
2
2
|
export class RPCError extends Error {
|
|
3
3
|
timestamp;
|
|
4
4
|
remoteStack;
|
|
@@ -93,14 +93,18 @@ function readOptionalStringField(fields, key) {
|
|
|
93
93
|
* be re-exported from `@qvac/sdk` so consumers can `import` it.
|
|
94
94
|
* Forgetting either side means `instanceof` regresses for that class.
|
|
95
95
|
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* envelope, and adding a reconstructor for one would create a
|
|
100
|
-
* parallel construction path that fires whenever the server happens
|
|
101
|
-
* to throw the same class name.
|
|
96
|
+
* Completion aggregators construct cancellation errors locally with partial
|
|
97
|
+
* output. RPC control operations also throw them in the worker, so cancellation
|
|
98
|
+
* errors support both paths.
|
|
102
99
|
*/
|
|
103
100
|
const RECONSTRUCTORS = {
|
|
101
|
+
INFERENCE_CANCELLED: (response) => {
|
|
102
|
+
const partial = response.typedFields?.['partial'];
|
|
103
|
+
return new InferenceCancelledError(readStringField(response.typedFields, 'requestId', ''), partial && typeof partial === 'object' && !Array.isArray(partial)
|
|
104
|
+
? partial
|
|
105
|
+
: {}, response.cause);
|
|
106
|
+
},
|
|
107
|
+
RPC_SERVER_OPERATION_FAILED: (response) => new RpcServerOperationError(readStringField(response.typedFields, 'operation', 'rpcServer'), readStringField(response.typedFields, 'details', response.message), response.cause),
|
|
104
108
|
REQUEST_ID_CONFLICT: (response) => {
|
|
105
109
|
return new RequestIdConflictError(readStringField(response.typedFields, 'requestId', ''), response.cause);
|
|
106
110
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export declare function generateWorkerEntry(pluginSpecifiers: string[], sdkName: string, resolveImport?: (specifier: string) => string): string;
|
|
2
|
-
export declare function generateWorkerEntries(pluginSpecifiers: string[], sdkName: string, resolveBundleImport: (specifier: string) => string): {
|
|
1
|
+
export declare function generateWorkerEntry(pluginSpecifiers: string[], sdkName: string, resolveImport?: (specifier: string) => string, rpcServerProvider?: string): string;
|
|
2
|
+
export declare function generateWorkerEntries(pluginSpecifiers: string[], sdkName: string, resolveBundleImport: (specifier: string) => string, rpcServerProvider?: string): {
|
|
3
3
|
runtimeEntry: string;
|
|
4
4
|
bundleEntry: string;
|
|
5
5
|
};
|