From e461cf59b52e09b7cd7c29ae7be333747ec96517 Mon Sep 17 00:00:00 2001 From: Bruno Campana <7632562+BrunoCampana@users.noreply.github.com> Date: Mon, 4 May 2026 11:01:04 -0300 Subject: [PATCH] doc: release v0.10.0 - API summary + release notes --- docs/website/content/docs/sdk/api/index.mdx | 78 +- docs/website/content/docs/sdk/api/v0.9.1.mdx | 1437 +++++++++++++++++ .../content/docs/sdk/release-notes/index.mdx | 491 ++++-- .../release-notes/{v0.9.0.mdx => v0.9.1.mdx} | 20 +- docs/website/package-lock.json | 464 +++--- docs/website/src/lib/versions.ts | 11 +- 6 files changed, 2105 insertions(+), 396 deletions(-) create mode 100644 docs/website/content/docs/sdk/api/v0.9.1.mdx rename docs/website/content/docs/sdk/release-notes/{v0.9.0.mdx => v0.9.1.mdx} (95%) diff --git a/docs/website/content/docs/sdk/api/index.mdx b/docs/website/content/docs/sdk/api/index.mdx index 9351408b89..3c35d1d847 100644 --- a/docs/website/content/docs/sdk/api/index.mdx +++ b/docs/website/content/docs/sdk/api/index.mdx @@ -1,7 +1,6 @@ --- -title: API Summary — v0.9.1 (latest) +title: API Summary — v0.10.0 (latest) description: One-page reference of all public functions and objects exported by @qvac/sdk -schemaType: APIReference --- > Auto-generated from `.d.ts` declarations and TSDoc comments. @@ -54,7 +53,7 @@ await cancel({ operation: "downloadAsset", downloadKey: "download-key", clearCac await cancel({ operation: "downloadAsset", downloadKey: "download-key", - delegate: { topic: "topicHex", providerPublicKey: "peerHex" }, + delegate: { providerPublicKey: "peerHex" }, }); ``` @@ -344,7 +343,7 @@ Can also be used to check if the local SDK worker is responsive. **Signature**: ```ts -function heartbeat(params?: { delegate?: { healthCheckTimeout?: number; providerPublicKey: string; timeout?: number; topic: string } }): Promise; +function heartbeat(params?: { delegate?: { healthCheckTimeout?: number; providerPublicKey: string; timeout?: number } }): Promise; ``` **Throws**: @@ -356,7 +355,7 @@ function heartbeat(params?: { delegate?: { healthCheckTimeout?: number; provider // Check if a delegated provider is online try { await heartbeat({ - delegate: { topic: "topicHex", providerPublicKey: "peerHex", timeout: 3000 }, + delegate: { providerPublicKey: "peerHex", timeout: 3000 }, }); console.log("Provider is online"); } catch { @@ -991,7 +990,14 @@ console.log(await state()); // "active" ### `startQVACProvider` Starts a provider service that offers QVAC capabilities to remote peers. -The provider's keypair can be controlled via the seed option or QVAC_HYPERSWARM_SEED environment variable. + +Consumers connect directly to the provider via its public key using +`dht.connect(publicKey)`, so no topic or discovery configuration is needed. +The provider's keypair (and therefore its public key) can be controlled via +the `QVAC_HYPERSWARM_SEED` environment variable. + +Idempotent: calling more than once while a provider is already running +returns the same public key without re-listening on the DHT. **Signature**: @@ -1001,7 +1007,7 @@ function startQVACProvider(params: ProvideParams): Promise<{ error?: string; pub **Throws**: -- `QvacErrorBase` — When the response type is not "provide" or the request fails. +- `QvacErrorBase` — When the response type is not "provide" or the request fails --- @@ -1035,17 +1041,26 @@ if (current !== "active") { ### `stopQVACProvider` -Stops a running provider service and leaves the specified topic. +Stops the running provider service. + +After this call returns, incoming peer connections are dropped at the RPC +layer and remote `loadModel`/`completion`/etc. requests will no longer be +served. The keyPair stays bound on the DHT (a `swarm.listen()` cannot be +undone without tearing down the shared swarm), so peers may still open a +raw socket — but those sockets are immediately destroyed and no RPC server +is mounted on them. + +Idempotent: calling more than once with no provider running is a no-op. **Signature**: ```ts -function stopQVACProvider(params: StopProvideParams): Promise<{ error?: string; success: boolean; type: "stopProvide" }>; +function stopQVACProvider(): Promise<{ error?: string; success: boolean; type: "stopProvide" }>; ``` **Throws**: -- `QvacErrorBase` — When the response type is not "stopProvide" or the request fails. +- `QvacErrorBase` — When the response type is not "stopProvide" or the request fails --- @@ -1141,6 +1156,19 @@ function textToSpeechStream(params: TextToSpeechStreamClientParams, options?: RP ### `transcribe` +Has 2 overloads. + +#### Overload 1 +Transcribe audio and return the complete text. Accepts either a file +path or an audio buffer. + +**Signature**: + +```ts +function transcribe(params: TranscribeClientParams & { metadata: true }, options?: RPCOptions): Promise; +``` + +#### Overload 2 Transcribe audio and return the complete text. Accepts either a file path or an audio buffer. @@ -1160,7 +1188,7 @@ removed in the next major version. Streaming transcription with upfront audio: sends full audio, yields text chunks as they arrive. -Has 2 overloads. +Has 4 overloads. #### Overload 1 — Upfront audio (deprecated) > ⚠️ **Deprecated**: Pass audio via `transcribe()` instead. This overload will be @@ -1171,11 +1199,24 @@ chunks as they arrive. **Signature**: +```ts +function transcribeStream(params: TranscribeClientParams & { metadata: true }, options?: RPCOptions): AsyncGenerator; +``` + +#### Overload 2 — Upfront audio (deprecated) +> ⚠️ **Deprecated**: Pass audio via `transcribe()` instead. This overload will be +removed in the next major version. + +Streaming transcription with upfront audio: sends full audio, yields text +chunks as they arrive. + +**Signature**: + ```ts function transcribeStream(params: TranscribeClientParams, options?: RPCOptions): AsyncGenerator; ``` -#### Overload 2 — Bidirectional session +#### Overload 3 — Bidirectional session Opens a bidirectional streaming transcription session. Audio is streamed in via `write()`, and transcription text is yielded as the model's VAD detects complete speech segments. @@ -1185,6 +1226,19 @@ time will throw a `TranscriptionFailedError`. **Signature**: +```ts +function transcribeStream(params: TranscribeStreamClientParams & { metadata: true }, options?: RPCOptions): Promise; +``` + +#### Overload 4 — Upfront audio (deprecated) +> ⚠️ **Deprecated**: Pass audio via `transcribe()` instead. This overload will be +removed in the next major version. + +Streaming transcription with upfront audio: sends full audio, yields text +chunks as they arrive. + +**Signature**: + ```ts function transcribeStream(params: TranscribeStreamClientParams, options?: RPCOptions): Promise; ``` diff --git a/docs/website/content/docs/sdk/api/v0.9.1.mdx b/docs/website/content/docs/sdk/api/v0.9.1.mdx new file mode 100644 index 0000000000..9351408b89 --- /dev/null +++ b/docs/website/content/docs/sdk/api/v0.9.1.mdx @@ -0,0 +1,1437 @@ +--- +title: API Summary — v0.9.1 (latest) +description: One-page reference of all public functions and objects exported by @qvac/sdk +schemaType: APIReference +--- + +> Auto-generated from `.d.ts` declarations and TSDoc comments. +> +> For per-parameter and per-field details, hover symbols in your IDE or open +> `node_modules/@qvac/sdk/dist`. This page is intentionally a high-level index. +> +> **Fields shown**: description, signature, throws, examples, deprecation. +> **Fields intentionally omitted**: parameter descriptions, return field descriptions +> (covered by IDE hover and `.d.ts` declarations). +> +> **Scope**: 38 functions in `packages/sdk/client/api/` plus the `profiler` object. + +--- + +## Functions + +### `cancel` + +Cancels an ongoing operation. + +**Signature**: + +```ts +function cancel(params: CancelParams): Promise; +``` + +**Throws**: + +- `QvacErrorBase` — When the response type is invalid or when the cancellation fails + +**Examples**: +```ts +// Cancel inference +await cancel({ operation: "inference", modelId: "model-123" }); +``` + +```ts +// Pause download (preserves partial file for automatic resume) +await cancel({ operation: "downloadAsset", downloadKey: "download-key" }); +``` + +```ts +// Cancel download completely (deletes partial file) +await cancel({ operation: "downloadAsset", downloadKey: "download-key", clearCache: true }); +``` + +```ts +// Cancel delegated remote download +await cancel({ + operation: "downloadAsset", + downloadKey: "download-key", + delegate: { topic: "topicHex", providerPublicKey: "peerHex" }, +}); +``` + +```ts +// Cancel RAG operation on default workspace +await cancel({ operation: "rag" }); +``` + +```ts +// Cancel RAG operation on specific workspace +await cancel({ operation: "rag", workspace: "my-workspace" }); +``` + +--- + +### `completion` + +Generates completion from a language model based on conversation history. + +Returns a `CompletionRun` whose canonical surfaces are: + + - `events` — `AsyncIterable` of ordered, typed events. + - `final` — `Promise` with aggregated results once the + stream ends (content, thinking, tool calls, stats, raw text). + +Legacy convenience fields (`tokenStream`, `text`, `toolCallStream`, +`toolCalls`, `stats`) are still available but deprecated — they derive +from `events` / `final` internally. + +**Signature**: + +```ts +function completion(params: CompletionParams): CompletionRun; +``` + +**Example**: +```ts +import { z } from "zod"; + +const run = completion({ + modelId: "llama-2", + history: [ + { role: "user", content: "What's the weather in Tokyo?" } + ], + stream: true, + captureThinking: true, + tools: [{ + name: "get_weather", + description: "Get current weather", + parameters: z.object({ + city: z.string().describe("City name"), + }), + handler: async (args) => { + return { temperature: 22, condition: "sunny" }; + } + }] +}); + +for await (const event of run.events) { + if (event.type === "contentDelta") process.stdout.write(event.text); + if (event.type === "toolCall") console.log(event.call.name, event.call.arguments); +} + +const result = await run.final; +for (const toolCall of await result.toolCalls) { + if (toolCall.invoke) { + const toolResult = await toolCall.invoke(); + console.log(toolResult); + } +} +``` + +--- + +### `deleteCache` + +Deletes KV cache files. + +**Signature**: + +```ts +function deleteCache(params: { all: true } | { kvCacheKey: string; modelId?: string }): Promise<{ success: boolean }>; +``` + +**Throws**: + +- `QvacErrorBase` — When the cache parameters are invalid (`InvalidDeleteCacheParamsError`) or the server reports a delete failure (`DeleteCacheFailedError`). + +**Example**: +```ts +// Delete all caches +await deleteCache({ all: true }); + +// Delete entire cache key (all models) +await deleteCache({ kvCacheKey: "my-session" }); + +// Delete only specific model within cache key +await deleteCache({ kvCacheKey: "my-session", modelId: "model-abc123" }); +``` + +--- + +### `diffusion` + +Generates images using a loaded diffusion model. + +**Signature**: + +```ts +function diffusion(params: DiffusionClientParams): DiffusionResult; +``` + +**Example**: +```ts +// txt2img +const { outputs, stats } = diffusion({ modelId, prompt: "a cat" }); +const buffers = await outputs; +fs.writeFileSync("output.png", buffers[0]); + +// img2img (SD/SDXL — SDEdit) +const initImage = fs.readFileSync("input.png"); +const { outputs } = diffusion({ modelId, prompt: "oil painting style", init_image: initImage, strength: 0.7 }); + +// img2img (FLUX.2 — in-context conditioning) +// IMPORTANT: FLUX img2img requires `prediction: "flux2_flow"` to be set on the +// model config at loadModel time (e.g. `loadModel(src, { modelType: "diffusion", +// modelConfig: { prediction: "flux2_flow" } })`). +const { outputs } = diffusion({ modelId, prompt: "turn into watercolor", init_image: initImage }); + +// With progress tracking +const { progressStream, outputs } = diffusion({ modelId, prompt: "a cat" }); +for await (const { step, totalSteps } of progressStream) { + console.log(`${step}/${totalSteps}`); +} +const buffers = await outputs; +``` + +--- + +### `downloadAsset` + +Downloads an asset (model file) without loading it into memory. + +This function is specifically designed for download-only operations and +doesn't accept runtime configuration options like modelConfig or delegate. +Use this for download-only operations instead of loadModel for better semantic clarity. + +**Signature**: + +```ts +function downloadAsset(options: DownloadAssetOptions, rpcOptions?: RPCOptions): Promise; +``` + +**Throws**: + +- `QvacErrorBase` — When asset download fails, with details in the error message +- `QvacErrorBase` — When streaming ends unexpectedly (only when using onProgress) +- `QvacErrorBase` — When receiving an invalid response type from the server + +**Example**: +```ts +// Download model without loading +const assetId = await downloadAsset({ + assetSrc: "/path/to/model.gguf", + seed: true +}); + +// Download with progress tracking +const assetId = await downloadAsset({ + assetSrc: "pear://key123/model.gguf", + onProgress: (progress) => { + console.log(`Downloaded: ${progress.percentage}%`); + } +}); +``` + +--- + +### `embed` + +Has 2 overloads. + +#### Overload 1 — Single text +Generates embeddings for a single text using a specified model. + +**Signature**: + +```ts +function embed(params: { modelId: string; text: string }, options?: RPCOptions): Promise<{ embedding: number[]; stats?: EmbedStats }>; +``` + +**Throws**: + +- `QvacErrorBase` — When the response type is invalid or when the embedding fails + +#### Overload 2 — Multiple texts +Generates embeddings for multiple texts using a specified model. + +**Signature**: + +```ts +function embed(params: { modelId: string; text: string[] }, options?: RPCOptions): Promise<{ embedding: number[][]; stats?: EmbedStats }>; +``` + +**Throws**: + +- `QvacErrorBase` — When the response type is invalid or when the embedding fails + +--- + +### `finetune` + +Has 2 overloads. + +#### Overload 1 — Run / start / resume +Run / start / resume a finetune job. Returns a handle with a streaming +`progressStream` and a terminal `result` promise. + +**Signature**: + +```ts +function finetune(params: FinetuneRunParams, rpcOptions?: RPCOptions): FinetuneHandle; +``` + +#### Overload 2 — Stop / getState / pause / cancel +Stop / pause / cancel an in-flight finetune, or query its current state. + +**Signature**: + +```ts +function finetune(params: FinetuneReplyParams, rpcOptions?: RPCOptions): Promise; +``` + +--- + +### `getLoadedModelInfo` + +Returns introspection info for a loaded `modelId` (local or delegated). + +For local models, `info.modelType` and `info.handlers` are authoritative. +Use them to preflight an SDK call before sending the actual RPC, e.g. +confirm that a model supports `transcribeStream` before calling `transcribe()`. + +For delegated models, only `modelId`, `isDelegated: true`, `providerInfo`, +and `handlers: []` are populated. Preflight against a delegated model is +best-effort and falls through to the provider's error response. + +Throws `ModelNotFoundError` if no entry exists for `modelId`. + +**Signature**: + +```ts +function getLoadedModelInfo(params: GetLoadedModelInfoParams, rpcOptions?: RPCOptions): Promise; +``` + +**Example**: +```ts +const info = await getLoadedModelInfo({ modelId }); +if (info.isDelegated || info.handlers.includes("completionStream")) { + // safe to call completion(); delegated path defers to provider +} +``` + +--- + +### `getModelInfo` + +Returns status information for a catalog model, including cache state and loaded instances. + +**Signature**: + +```ts +function getModelInfo(params: GetModelInfoParams): Promise<{ actualSize?: number; addon: "llm" | "whisper" | "embeddings" | "nmt" | "vad" | "tts" | "ocr" | "parakeet" | "diffusion" | "other"; blobBlockLength?: number; blobBlockOffset?: number; blobByteOffset?: number; blobCoreKey?: string; cachedAt?: Date; cacheFiles: { actualSize?: number; cachedAt?: Date; expectedSize: number; filename: string; isCached: boolean; path: string; sha256Checksum: string }[]; engine?: string; expectedSize: number; isCached: boolean; isLoaded: boolean; loadedInstances?: { config?: unknown; loadedAt: Date; registryId: string }[]; modelId: string; name: string; params?: string; quantization?: string; registryPath?: string; registrySource?: string; sha256Checksum: string }>; +``` + +**Throws**: + +- `QvacErrorBase` — When the response type is invalid (`InvalidResponseError`) or the RPC layer fails. + +--- + +### `heartbeat` + +Checks if a delegated provider is online by sending a heartbeat round-trip. +Can also be used to check if the local SDK worker is responsive. + +**Signature**: + +```ts +function heartbeat(params?: { delegate?: { healthCheckTimeout?: number; providerPublicKey: string; timeout?: number; topic: string } }): Promise; +``` + +**Throws**: + +- `QvacErrorBase` — When the provider is unreachable or the response is invalid. + +**Examples**: +```ts +// Check if a delegated provider is online +try { + await heartbeat({ + delegate: { topic: "topicHex", providerPublicKey: "peerHex", timeout: 3000 }, + }); + console.log("Provider is online"); +} catch { + console.log("Provider is offline"); +} +``` + +```ts +// Check if the local SDK worker is responsive +await heartbeat(); +``` + +--- + +### `invokePlugin` + +Invoke a non-streaming plugin handler. + +**Signature**: + +```ts +function invokePlugin(options: InvokePluginOptions, rpcOptions?: RPCOptions): Promise; +``` + +**Throws**: + +- `QvacErrorBase` — When the response type is invalid (`InvalidResponseError`) or the RPC layer fails. + +--- + +### `invokePluginStream` + +Invoke a streaming plugin handler. + +**Signature**: + +```ts +function invokePluginStream(options: InvokePluginOptions, rpcOptions?: RPCOptions): AsyncGenerator; +``` + +**Throws**: + +- `QvacErrorBase` — When an intermediate response has the wrong type (`InvalidResponseError`) or the RPC layer fails. + +--- + +### `loadModel` + +Has 4 overloads. + +#### Overload 1 — From descriptor +Loads a model from a descriptor; `modelType` is inferred from `modelSrc`. +`modelConfig` narrows per-engine when `modelSrc.engine` is a literal, +otherwise falls back to a permissive shape. + +**Signature**: + +```ts +function loadModel(options: LoadModelDescriptorParam, rpcOptions?: RPCOptions): Promise; +``` + +**Throws**: + +- `ModelTypeRequiredError` — When `modelType` cannot be inferred from `modelSrc` at runtime. + +**Example**: +```ts +await loadModel({ modelSrc: LLAMA_3_2_1B_INST_Q4_0, modelConfig: { ctx_size: 2048 } }); +await loadModel({ modelSrc: WHISPER_TINY }); +``` + +#### Overload 2 — Load new model +Loads a machine learning model from a local path, remote URL, or Hyperdrive key. + +This function supports multiple model types: LLM (Large Language Model), Whisper (speech recognition), +embeddings, NMT (translation), and TTS. It can handle both local file paths and Hyperdrive URLs (pear://). + +When `onProgress` is provided, the function uses streaming to provide real-time download progress. +Otherwise, it uses a simple request-response pattern for faster execution. + +**Signature**: + +```ts +function loadModel(options: LoadModelOptions, rpcOptions?: RPCOptions): Promise; +``` + +**Throws**: + +- `QvacErrorBase` — When model loading fails, with details in the error message +- `QvacErrorBase` — When streaming ends unexpectedly (only when using onProgress) +- `QvacErrorBase` — When receiving an invalid response type from the server + +**Example**: +```ts +// Local file path - absolute path +const localModelId = await loadModel({ + modelSrc: "/home/user/models/llama-7b.gguf", + modelType: "llm", + modelConfig: { ctx_size: 2048 } +}); + +// Local file path - relative path +const relativeModelId = await loadModel({ + modelSrc: "./models/whisper-base.gguf", + modelType: "whisper" +}); + +// Hyperdrive URL with key and path +const hyperdriveId = await loadModel({ + modelSrc: "pear:///llama-7b.gguf", + modelType: "llm", + modelConfig: { ctx_size: 2048 } +}); + +// Remote HTTP/HTTPS URL with progress tracking +const remoteId = await loadModel({ + modelSrc: "https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGUF/resolve/main/llama-2-7b-chat.Q4_K_M.gguf", + modelType: "llm", + onProgress: (progress) => { + console.log(`Downloaded: ${progress.percentage}%`); + } +}); + +// Multimodal model with projection +const multimodalId = await loadModel({ + modelSrc: "https://huggingface.co/.../main-model.gguf", + modelType: "llm", + modelConfig: { + ctx_size: 512, + projectionModelSrc: "https://huggingface.co/.../projection-model.gguf" + }, + onProgress: (progress) => { + console.log(`Loading: ${progress.percentage}%`); + } +}); + +// Whisper with VAD model +const whisperId = await loadModel({ + modelSrc: "https://huggingface.co/.../whisper-model.gguf", + modelType: "whisper", + modelConfig: { + mode: "caption", + output_format: "plaintext", + min_seconds: 2, + max_seconds: 6, + vadModelSrc: "https://huggingface.co/.../vad-model.bin" + } +}); + +// Load with automatic logging - logs from the model will be forwarded to your logger +import { getLogger } from "@/logging"; +const logger = getLogger("my-app"); + +const modelId = await loadModel({ + modelSrc: "/path/to/model.gguf", + modelType: "llm", + logger // Pass logger in options +}); +``` + +#### Overload 3 — Custom plugin +Loads a custom plugin model (any non-built-in `modelType` string). +`modelConfig` is plugin-defined; the SDK does not narrow it. + +**Signature**: + +```ts +function loadModel(options: LoadCustomPluginModelOptions, rpcOptions?: RPCOptions): Promise; +``` + +#### Overload 4 — Hot-reload config +Hot-reloads configuration on an already loaded model. + +**Signature**: + +```ts +function loadModel(options: ReloadConfigOptions, rpcOptions?: RPCOptions): Promise; +``` + +**Throws**: + +- `QvacErrorBase` — When model reload fails, with details in the error message +- `QvacErrorBase` — When receiving an invalid response type from the server + +**Example**: +```ts +// Load new model +const modelId = await loadModel({ + modelSrc: "pear:///whisper-tiny.gguf", + modelType: "whisper", + modelConfig: { language: "en" }, +}); + +// Later, update the config without reloading the model +await loadModel({ + modelId, + modelType: "whisper", + modelConfig: { language: "es" }, +}); +``` + +--- + +### `loggingStream` + +Opens a logging stream to receive real-time logs. + +**Signature**: + +```ts +function loggingStream(params: LoggingParams): AsyncGenerator; +``` + +**Throws**: + +- `QvacErrorBase` — When the response type is invalid or when the stream fails + +**Example**: +```ts +// Open a logging stream for a model +const logStream = loggingStream({ id: 'my-model-id' }); + +// Or stream SDK server logs +const sdkLogs = loggingStream({ id: SDK_LOG_ID }); + +for await (const logMessage of logStream) { + console.log(`[${logMessage.level}] ${logMessage.namespace}: ${logMessage.message}`); +} +``` + +--- + +### `modelRegistryGetModel` + +Fetches a single model entry from the registry by its path and source. + +**Signature**: + +```ts +function modelRegistryGetModel(registryPath: string, registrySource: string): Promise; +``` + +**Throws**: + +- `ModelRegistryQueryFailedError` — When the model cannot be located or the registry query fails. + +--- + +### `modelRegistryList` + +Returns all available models from the QVAC distributed model registry. + +**Signature**: + +```ts +function modelRegistryList(): Promise; +``` + +**Throws**: + +- `ModelRegistryQueryFailedError` — When the registry query fails. + +--- + +### `modelRegistrySearch` + +Searches the model registry with optional filters for model type, engine, and quantization. + +**Signature**: + +```ts +function modelRegistrySearch(params: ModelRegistrySearchParams): Promise; +``` + +**Throws**: + +- `ModelRegistryQueryFailedError` — When the registry query fails. + +--- + +### `ocr` + +Performs Optical Character Recognition (OCR) on an image to extract text. + +**Signature**: + +```ts +function ocr(params: OCRClientParams): { blocks: Promise<{ bbox?: [number, number, number, number]; confidence?: number; text: string }[]>; blockStream: AsyncGenerator<{ bbox?: [number, number, number, number]; confidence?: number; text: string }[]>; stats: Promise<{ detectionTime?: number; recognitionTime?: number; totalTime?: number } | undefined> }; +``` + +**Example**: +```ts +// Non-streaming mode (default) - get all blocks at once +const { blocks } = ocr({ modelId, image: "/path/to/image.png" }); +for (const block of await blocks) { + console.log(block.text, block.bbox, block.confidence); +} + +// Streaming mode - process blocks as they arrive +const { blockStream } = ocr({ modelId, image: imageBuffer, stream: true }); +for await (const blocks of blockStream) { + console.log("Detected:", blocks); +} +``` + +--- + +### `ragChunk` + +Chunks documents into smaller pieces for embedding. +Part of the segregated flow: ragChunk() → embed() → ragSaveEmbeddings() + +**Signature**: + +```ts +function ragChunk(params: RagChunkParams, options?: RPCOptions): Promise; +``` + +**Throws**: + +- `RAGChunkFailedError` — When the operation fails + +**Example**: +```ts +const chunks = await ragChunk({ + documents: ["Long document text here..."], + chunkOpts: { + chunkSize: 256, + chunkOverlap: 50, + chunkStrategy: "paragraph", + }, +}); +``` + +--- + +### `ragCloseWorkspace` + +Closes a RAG workspace, releasing in-memory resources (Corestore, HyperDB adapter, RAG instance). + +**Workspace lifecycle:** Workspaces are implicitly opened. +This function explicitly closes them, releasing memory and file locks. The workspace data +remains on disk unless `deleteOnClose` is set to true. + +**Signature**: + +```ts +function ragCloseWorkspace(params?: RagCloseWorkspaceParams, options?: RPCOptions): Promise; +``` + +**Throws**: + +- `RAGCloseWorkspaceFailedError` — When the operation fails + +**Example**: +```ts +// Close a specific workspace +await ragCloseWorkspace({ workspace: "my-docs" }); + +// Close and delete in one call +await ragCloseWorkspace({ workspace: "my-docs", deleteOnClose: true }); +``` + +--- + +### `ragDeleteEmbeddings` + +Deletes document embeddings from the RAG vector database. + +**Workspace lifecycle:** This operation requires an existing workspace. + +**Signature**: + +```ts +function ragDeleteEmbeddings(params: RagDeleteEmbeddingsParams, options?: RPCOptions): Promise; +``` + +**Throws**: + +- `RAGDeleteFailedError` — When the operation fails or workspace doesn't exist + +**Example**: +```ts +await ragDeleteEmbeddings({ + ids: ["doc-1", "doc-2"], + workspace: "my-docs", +}); +``` + +--- + +### `ragDeleteWorkspace` + +Deletes a RAG workspace and all its data. +The workspace must not be currently loaded/in-use. + +**Signature**: + +```ts +function ragDeleteWorkspace(params: RagDeleteWorkspaceParams, options?: RPCOptions): Promise; +``` + +**Throws**: + +- `RAGDeleteFailedError` — When the workspace doesn't exist or is currently loaded + +**Example**: +```ts +await ragDeleteWorkspace({ workspace: "my-docs" }); +``` + +--- + +### `ragIngest` + +Ingests documents into the RAG vector database. +Full pipeline: chunk → embed → save + +**Workspace lifecycle:** This operation implicitly opens (or creates) the workspace. +The workspace remains open until closed. + +**Signature**: + +```ts +function ragIngest(params: RagIngestParams, options?: RPCOptions): Promise<{ processed: RagSaveEmbeddingsResult[]; droppedIndices: number[] }>; +``` + +**Throws**: + +- `RAGSaveFailedError` — When the operation fails +- `StreamEndedError` — When streaming ends unexpectedly (only when using onProgress) + +**Example**: +```ts +// Simple ingest +const result = await ragIngest({ + modelId, + documents: ["Document 1", "Document 2"], +}); + +// With progress tracking +const result = await ragIngest({ + modelId, + documents: ["Document 1", "Document 2"], + workspace: "my-docs", + onProgress: (stage, current, total) => { + console.log(`[${stage}] ${current}/${total}`); + }, +}); +``` + +--- + +### `ragListWorkspaces` + +Lists all RAG workspaces with their open status. + +Returns all workspaces that exist on disk. The `open` field indicates whether +the workspace is currently loaded in memory and holding active resources +(Corestore, HyperDB adapter, and possibly a RAG instance). + +**Signature**: + +```ts +function ragListWorkspaces(options?: RPCOptions): Promise; +``` + +**Throws**: + +- `RAGListWorkspacesFailedError` — When the operation fails + +**Example**: +```ts +const workspaces = await ragListWorkspaces(); +// [{ name: "default", open: true }, { name: "my-docs", open: false }] +``` + +--- + +### `ragReindex` + +Reindexes the RAG database to optimize search performance. +For HyperDB, this rebalances centroids using k-means clustering. + +**Workspace lifecycle:** This operation requires an existing workspace. + +**Note:** Reindex requires a minimum number of documents to perform clustering. +For HyperDB, this is 16 documents by default. If there are insufficient documents, +`reindexed` will be `false` with `details` explaining the reason. + +**Signature**: + +```ts +function ragReindex(params: RagReindexParams, options?: RPCOptions): Promise; +``` + +**Throws**: + +- `RAGSaveFailedError` — When the operation fails or workspace doesn't exist +- `StreamEndedError` — When streaming ends unexpectedly (only when using onProgress) + +**Example**: +```ts +// Simple reindex +const result = await ragReindex({ + workspace: "my-docs", +}); + +// Check result +if (!result.reindexed) { + console.log("Reindex skipped:", result.details?.reason); +} + +// With progress tracking +const result = await ragReindex({ + workspace: "my-docs", + onProgress: (stage, current, total) => { + console.log(`[${stage}] ${current}/${total}`); + }, +}); +``` + +--- + +### `ragSaveEmbeddings` + +Saves pre-embedded documents to the RAG vector database. +Part of the segregated flow: chunk() → embed() → saveEmbeddings() + +**Workspace lifecycle:** This operation implicitly opens (or creates) the workspace. +The workspace remains open until closed. + +**Signature**: + +```ts +function ragSaveEmbeddings(params: RagSaveEmbeddingsParams, options?: RPCOptions): Promise; +``` + +**Throws**: + +- `RAGSaveFailedError` — When the operation fails +- `StreamEndedError` — When streaming ends unexpectedly (only when using onProgress) + +**Example**: +```ts +// Segregated flow +const chunks = await ragChunk({ documents: ["text1", "text2"] }); +const { embedding: embeddings } = await embed({ modelId, text: chunks.map(c => c.content) }); +const embeddedDocs = chunks.map((chunk, i) => ({ + ...chunk, + embedding: embeddings[i], + embeddingModelId: modelId, +})); +const result = await ragSaveEmbeddings({ + documents: embeddedDocs, + workspace: "my-workspace", +}); +``` + +--- + +### `ragSearch` + +Searches for similar documents in the RAG vector database. + +**Workspace lifecycle:** This operation requires an existing workspace. If the workspace +doesn't exist, returns an empty array. + +**Signature**: + +```ts +function ragSearch(params: RagSearchParams, options?: RPCOptions): Promise; +``` + +**Throws**: + +- `RAGSearchFailedError` — When the operation fails + +**Example**: +```ts +const results = await ragSearch({ + modelId, + query: "AI and machine learning", + topK: 5, + workspace: "my-docs", +}); +``` + +--- + +### `resume` + +Resumes the SDK runtime: restores all suspended Hyperswarm and Corestore +resources and releases the lifecycle gate so all SDK operations are allowed +again. + +Safe to call from any lifecycle state — `resume()` is never blocked by the +lifecycle gate (along with `suspend()` and `state()`). Idempotent. Also +serves as the recovery path after a partial suspend failure. + +After `resume()` resolves successfully, runtime state is `"active"` and +non-lifecycle SDK operations are accepted normally. + +Behavior of in-flight operations from before the previous `suspend()`: + - P2P / Hyperdrive downloads: continue automatically once their underlying + swarm/corestore is restored + - Delegated reply RPCs: auto-recover once the swarm reconnects + (subject to delegate `timeout`) + - Delegated stream RPCs: not recovered — re-issue after `resume()` works normally. + +**Signature**: + +```ts +function resume(): Promise; +``` + +**Throws**: + +- `RPCError` — When one or more resources fail to resume. On partial + failure the runtime stays `"suspended"` (operations remain blocked) so + callers can retry `resume()`. + +**Example**: +```ts +// Foreground handler +await resume(); +console.log(await state()); // "active" +``` + +--- + +### `startQVACProvider` + +Starts a provider service that offers QVAC capabilities to remote peers. +The provider's keypair can be controlled via the seed option or QVAC_HYPERSWARM_SEED environment variable. + +**Signature**: + +```ts +function startQVACProvider(params: ProvideParams): Promise<{ error?: string; publicKey?: string; success: boolean; type: "provide" }>; +``` + +**Throws**: + +- `QvacErrorBase` — When the response type is not "provide" or the request fails. + +--- + +### `state` + +Returns the current runtime lifecycle state. + +Safe to call from any lifecycle state — `state()` is never blocked by the +lifecycle gate (along with `suspend()` and `resume()`). + +**Signature**: + +```ts +function state(): Promise; +``` + +**Throws**: + +- `InvalidResponseError` — When the response envelope does not match the request type. + +**Example**: +```ts +// Branch on lifecycle state before issuing work +const current = await state(); +if (current !== "active") { + await resume(); +} +``` + +--- + +### `stopQVACProvider` + +Stops a running provider service and leaves the specified topic. + +**Signature**: + +```ts +function stopQVACProvider(params: StopProvideParams): Promise<{ error?: string; success: boolean; type: "stopProvide" }>; +``` + +**Throws**: + +- `QvacErrorBase` — When the response type is not "stopProvide" or the request fails. + +--- + +### `suspend` + +Suspends the SDK runtime: pauses all registered Hyperswarm and Corestore +resources and engages the lifecycle gate so non-lifecycle operations are +blocked until `resume()` is called. + +Safe to call from any lifecycle state — `suspend()` is never blocked by the +lifecycle gate (along with `resume()` and `state()`). Idempotent. + +After `suspend()` resolves, runtime state is `"suspended"` and any non- +lifecycle SDK operation throws `LifecycleOperationBlockedError` until +`resume()` is called. + +In-flight operations started before suspend: + - P2P / Hyperdrive downloads: stall cleanly, continue after `resume()` + - HTTP downloads: bypass suspend entirely (bytes keep flowing) + - Local native inference: runs to completion regardless + - Delegated reply RPCs: stall, then auto-recover after `resume()` + (subject to delegate `timeout`) + - Delegated stream RPCs: severed, consumer iterator hangs silently; + re-issue after `resume()` works normally. + +**Signature**: + +```ts +function suspend(): Promise; +``` + +**Throws**: + +- `RPCError` — When one or more resources fail to suspend. The runtime + still commits to `"suspended"` so callers can recover with `resume()`. + +**Example**: +```ts +// Background handler +await suspend(); +console.log(await state()); // "suspended" +``` + +--- + +### `textToSpeech` + +Converts text to speech audio using a loaded TTS model. + +Three modes selected by `params.stream` and `params.sentenceStream`: + +- `stream: false` (default) — collect all PCM samples and resolve once via + `result.buffer` (`Promise`). `bufferStream` is empty. +- `stream: true` — yield PCM samples through `result.bufferStream` + (`AsyncGenerator`) as they arrive. `buffer` resolves to an empty + array. +- `stream: true, sentenceStream: true` — also exposes `result.chunkUpdates` + (`AsyncGenerator`) so callers can mux per-sentence + metadata with the audio. Multiple consumers can iterate the response + independently via the underlying `TtsMulticast`. + +`result.done` resolves to `true` when synthesis completes cleanly, `false` +if the consumer breaks out before the terminal frame, or rejects on a +pipeline error. Awaiting `done` is safe even when no stream is iterated. + +**Signature**: + +```ts +function textToSpeech(params: TtsClientParamsInput, options?: RPCOptions): TextToSpeechStreamResult; +``` + +**Throws**: + +- `TextToSpeechStreamFailedError` — When `sentenceStream: true` is paired + with `stream: false`, or when the underlying RPC stream errors. + +--- + +### `textToSpeechStream` + +Duplex session: write UTF-8 text fragments (e.g. LLM token deltas) via `write`. Each string or +Buffer should be a complete UTF-8 fragment. The worker forwards them to ONNX TTS `runStreaming` +(optional sentence accumulation via request fields). Iterate the session for `TextToSpeechStreamResponse` +lines (PCM in `buffer`, optional `chunkIndex` / `sentenceChunk`) until `done`. + +**Signature**: + +```ts +function textToSpeechStream(params: TextToSpeechStreamClientParams, options?: RPCOptions): Promise; +``` + +--- + +### `transcribe` + +Transcribe audio and return the complete text. Accepts either a file +path or an audio buffer. + +**Signature**: + +```ts +function transcribe(params: TranscribeClientParams, options?: RPCOptions): Promise; +``` + +--- + +### `transcribeStream` + +> ⚠️ **Deprecated**: Pass audio via `transcribe()` instead. This overload will be +removed in the next major version. + +Streaming transcription with upfront audio: sends full audio, yields text +chunks as they arrive. + +Has 2 overloads. + +#### Overload 1 — Upfront audio (deprecated) +> ⚠️ **Deprecated**: Pass audio via `transcribe()` instead. This overload will be +removed in the next major version. + +Streaming transcription with upfront audio: sends full audio, yields text +chunks as they arrive. + +**Signature**: + +```ts +function transcribeStream(params: TranscribeClientParams, options?: RPCOptions): AsyncGenerator; +``` + +#### Overload 2 — Bidirectional session +Opens a bidirectional streaming transcription session. Audio is streamed +in via `write()`, and transcription text is yielded as the model's VAD +detects complete speech segments. + +The returned session is single-use. Attempting to iterate a second +time will throw a `TranscriptionFailedError`. + +**Signature**: + +```ts +function transcribeStream(params: TranscribeStreamClientParams, options?: RPCOptions): Promise; +``` + +--- + +### `translate` + +Translates text from one language to another using a specified translation model. +Supports both NMT (Neural Machine Translation) and LLM models. + +**Signature**: + +```ts +function translate(params: TranslateClientParams, options?: RPCOptions): { stats: Promise<{ cacheTokens?: number; decodeTime?: number; encodeTime?: number; timeToFirstToken?: number; tokensPerSecond?: number; totalTime?: number; totalTokens?: number } | undefined>; text: Promise; tokenStream: AsyncGenerator }; +``` + +**Throws**: + +- `QvacErrorBase` — When translation fails with an error message or when language detection fails + +**Example**: +```ts +// Streaming mode (default) +const result = translate({ + modelId: "modelId", + text: "Hello world", + from: "en", + to: "es" + modelType: "llm", +}); + +for await (const token of result.tokenStream) { + console.log(token); +} + +// Non-streaming mode +const response = translate({ + modelId: "modelId", + text: "Hello world", + from: "en", + to: "es" + modelType: "llm", + stream: false, +}); + +console.log(await response.text); +``` + +--- + +### `unloadModel` + +Unloads a previously loaded model from the server. + +When the last model is unloaded (no more models remain), this function +automatically closes the RPC connection, allowing the process to exit +naturally without requiring manual cleanup. + +**Signature**: + +```ts +function unloadModel(params: UnloadModelParams): Promise; +``` + +**Throws**: + +- `QvacErrorBase` — When the response type is invalid or when the unload operation fails + +--- + +## Objects + +### `profiler` + +QVAC SDK Profiler + +**Shape**: + +```ts +const profiler: { + clear(): void; + disable(): void; + enable(options?: ProfilerRuntimeOptions): void; + exportJSON(options?: { includeRecentEvents?: boolean }): ProfilerExport; + exportSummary(): string; + exportTable(): string; + getAggregates(): Record; + getConfig(): ResolvedProfilerConfig; + isEnabled(): boolean; + onRecord(callback: (event: ProfilingEvent) => void): () => void; +}; +``` + +**Methods**: + +- **`clear()`** — Clears all aggregated data and the recent-events ring buffer. +- **`disable()`** — Disables profiling. +- **`enable(options?)`** — Enables profiling and resets all previously aggregated data. +- **`exportJSON(options?)`** — Exports profiling data as a structured JSON object suitable for machine consumption. +- **`exportSummary()`** — Exports a short, human-readable summary string of the aggregated stats. +- **`exportTable()`** — Exports aggregated stats as a formatted ASCII table suitable for terminal output. +- **`getAggregates()`** — Returns all aggregated stats keyed by operation name. +- **`getConfig()`** — Returns the current effective profiler configuration. +- **`isEnabled()`** — Returns whether profiling is currently enabled. +- **`onRecord(callback)`** — Registers a listener for profiling events; returns an unsubscribe function. + +**Example**: +```ts +import { profiler } from "@qvac/sdk"; + +profiler.enable({ mode: "summary" }); +// ... run SDK operations ... +console.log(profiler.exportTable()); +profiler.disable(); +``` + +--- + +## Errors + +Public error codes thrown across the SDK. Catch via `instanceof QvacErrorBase` +and read `error.code` / `error.cause`. Code ranges: +50,001–52,000 (client) and 52,001–54,000 (server). + +### Client errors + +| Error | Code | Summary | +| --- | --- | --- | +| `INVALID_RESPONSE_TYPE` | 50001 | Invalid response type received, expected: … | +| `INVALID_OPERATION_IN_RESPONSE` | 50002 | Invalid operation type in response | +| `STREAM_ENDED_WITHOUT_RESPONSE` | 50003 | Stream ended without receiving final response | +| `INVALID_AUDIO_CHUNK_TYPE` | 50004 | Invalid audio chunk type received | +| `INVALID_TOOLS_ARRAY` | 50005 | Invalid tools array provided | +| `INVALID_TOOL_SCHEMA` | 50006 | Invalid tool schema: … | +| `OCR_FAILED` | 50007 | OCR operation failed… | +| `MODEL_TYPE_REQUIRED` | 50008 | modelType is required: modelSrc is a plain string or lacks an engine/addon descriptor that can be inferred. Pass an explicit canonical modelType (e.g. "llamacpp-completion", "whispercpp-transcription", "nmtcpp-translation", "llamacpp-embedding", "onnx-tts", "onnx-ocr", "parakeet-transcription", "sdcpp-generation") or use a model constant that carries engine metadata. | +| `MODEL_SRC_TYPE_MISMATCH` | 50009 | modelSrc describes "…", but modelType resolves to "…". Omit modelType to infer it automatically, or pass a matching modelType. | +| `RPC_NO_HANDLER` | 50200 | No handler function registered for request type: … | +| `RPC_REQUEST_NOT_SENT` | 50201 | Cannot perform operation - request has not been sent yet | +| `RPC_RESPONSE_STREAM_NOT_CREATED` | 50202 | Cannot perform operation - response stream not created | +| `RPC_CONNECTION_FAILED` | 50203 | RPC connection failed: … | +| `RPC_INIT_TIMEOUT` | 50204 | RPC initialization timed out after …ms — the worker process may have failed to start | +| `PROVIDER_START_FAILED` | 50400 | Failed to start provider… | +| `PROVIDER_STOP_FAILED` | 50401 | Failed to stop provider… | +| `DELEGATE_NO_FINAL_RESPONSE` | 50402 | No final response received from delegated provider | +| `DELEGATE_PROVIDER_ERROR` | 50403 | Delegated provider error: … | +| `DELEGATE_CONNECTION_FAILED` | 50404 | Failed to connect to delegated provider: … | +| `SDK_NOT_FOUND_IN_NODE_MODULES` | 50600 | QVAC SDK not found in node_modules. Checked: @qvac/sdk, @tetherto/sdk-mono, @tetherto/sdk-dev | +| `WORKER_FILE_NOT_FOUND` | 50601 | Worker file not found at … | +| `CONFIG_FILE_NOT_FOUND` | 50602 | Config file not found. Searched: …. Create qvac.config.json, qvac.config.js, or qvac.config.ts in your project root. | +| `CONFIG_FILE_INVALID` | 50603 | Config file at … is invalid: … | +| `CONFIG_FILE_PARSE_FAILED` | 50604 | Failed to parse config file at …: … | +| `CONFIG_VALIDATION_FAILED` | 50605 | Config validation failed: … | +| `PEAR_WORKER_ENTRY_REQUIRED` | 50606 | No plugins registered. Pear apps must spawn … as the worker entry. Run \\ | +| `MULTIPLE_SDK_INSTALLATIONS` | 50607 | Multiple QVAC SDK installations found: …. Remove all but one to avoid conflicts. | +| `PROFILER_INVALID_CAPACITY` | 50800 | Ring buffer capacity must be at least … | + +### Server errors + +| Error | Code | Summary | +| --- | --- | --- | +| `MODEL_ALREADY_REGISTERED` | 52001 | Model with ID "…" is already registered | +| `MODEL_NOT_FOUND` | 52002 | Model with ID "…" not found | +| `MODEL_NOT_LOADED` | 52003 | Model with ID "…" is not loaded | +| `MODEL_IS_DELEGATED` | 52004 | Model "…" is a delegated model and cannot be accessed directly | +| `UNKNOWN_MODEL_TYPE` | 52005 | Unknown model type: …. If using a custom worker bundle, ensure the plugin for "…" is included in your qvac.config plugins array and rebuild with "npx qvac bundle sdk". | +| `MODEL_LOAD_FAILED` | 52200 | Failed to load model… | +| `MODEL_FILE_NOT_FOUND` | 52201 | Model file not found: … | +| `MODEL_FILE_NOT_FOUND_IN_DIR` | 52202 | … model file … not found in directory … | +| `MODEL_FILE_LOCATE_FAILED` | 52203 | Failed to locate … model file: … | +| `PROJECTION_MODEL_REQUIRED` | 52204 | Projection model source is required for multimodal LLM models | +| `VAD_MODEL_REQUIRED` | 52205 | VAD model source is required for this configuration | +| `TTS_ARTIFACTS_REQUIRED` | 52208 | TTS (Chatterbox) requires ttsTokenizerSrc, ttsSpeechEncoderSrc, ttsEmbedTokensSrc, ttsConditionalDecoderSrc, and ttsLanguageModelSrc | +| `TTS_REFERENCE_AUDIO_REQUIRED` | 52209 | TTS (Chatterbox) requires referenceAudioSrc (path or URL to a WAV file for voice cloning) | +| `PARAKEET_ARTIFACTS_REQUIRED` | 52210 | Parakeet model sources are missing. TDT requires parakeetEncoderSrc, parakeetDecoderSrc, parakeetVocabSrc, parakeetPreprocessorSrc. CTC requires parakeetCtcModelSrc, parakeetTokenizerSrc. Sortformer requires parakeetSortformerSrc. | +| `MODEL_UNLOAD_FAILED` | 52400 | Failed to unload model… | +| `EMBED_FAILED` | 52401 | Failed to generate embeddings… | +| `EMBED_NO_EMBEDDINGS` | 52402 | No embeddings returned from model | +| `TRANSCRIPTION_FAILED` | 52403 | Transcription failed… | +| `AUDIO_FILE_NOT_FOUND` | 52404 | Audio file not found or not accessible: … | +| `TRANSLATION_FAILED` | 52405 | Translation failed… | +| `COMPLETION_FAILED` | 52406 | Completion failed… | +| `ATTACHMENT_NOT_FOUND` | 52407 | Attachment not found at path: … | +| `CANCEL_FAILED` | 52408 | Failed to cancel operation… | +| `TEXT_TO_SPEECH_FAILED` | 52409 | Text-to-speech operation failed… | +| `CONFIG_RELOAD_NOT_SUPPORTED` | 52410 | Model "…" does not support hot config reload | +| `MODEL_TYPE_MISMATCH` | 52411 | Model type mismatch: expected "…", got "…" | +| `OCR_FAILED` | 52412 | OCR operation failed… | +| `IMAGE_FILE_NOT_FOUND` | 52413 | Image file not found or not accessible: … | +| `INVALID_IMAGE_INPUT` | 52414 | Invalid image input type provided | +| `TEXT_TO_SPEECH_STREAM_FAILED` | 52415 | Text-to-speech stream operation failed… | +| `MODEL_OPERATION_NOT_SUPPORTED` | 52416 | Supported operations on this model: …. | +| `RAG_SAVE_FAILED` | 52800 | Failed to save embeddings… | +| `RAG_SEARCH_FAILED` | 52801 | Failed to search embeddings… | +| `RAG_DELETE_FAILED` | 52802 | Failed to delete embeddings… | +| `RAG_UNKNOWN_OPERATION` | 52803 | Unknown RAG operation: … | +| `RAG_HYPERDB_FAILED` | 52804 | HyperDB RAG operation failed: … | +| `RAG_WORKSPACE_MODEL_MISMATCH` | 52805 | Workspace "…" is configured for model "…", but you're trying to use model "…". Use a different workspace or the same model | +| `RAG_WORKSPACE_NOT_FOUND` | 52806 | RAG workspace not found: … | +| `RAG_WORKSPACE_IN_USE` | 52807 | RAG workspace '…' is currently in use. Close it first. | +| `RAG_WORKSPACE_CLOSE_FAILED` | 52808 | Failed to close RAG workspace… | +| `RAG_LIST_WORKSPACES_FAILED` | 52809 | Failed to list RAG workspaces… | +| `RAG_CHUNK_FAILED` | 52810 | Failed to chunk documents… | +| `RAG_WORKSPACE_NOT_OPEN` | 52811 | RAG workspace '…' is not open | +| `FILE_NOT_FOUND` | 53000 | File not found: … | +| `DOWNLOAD_CANCELLED` | 53001 | Download was cancelled | +| `CHECKSUM_VALIDATION_FAILED` | 53002 | Checksum validation failed for … | +| `HTTP_ERROR` | 53003 | HTTP error: … … | +| `NO_RESPONSE_BODY` | 53004 | No response body received from HTTP request | +| `RESPONSE_BODY_NOT_READABLE` | 53005 | Response body is not readable | +| `NO_BLOB_FOUND` | 53006 | No blob found for … | +| `DOWNLOAD_ASSET_FAILED` | 53007 | Failed to download asset… | +| `SEEDING_NOT_SUPPORTED` | 53008 | Seeding is only supported for hyperdrive models | +| `HYPERDRIVE_DOWNLOAD_FAILED` | 53009 | Hyperdrive download failed: … | +| `INVALID_SHARD_URL_PATTERN` | 53010 | URL does not contain a valid sharded model pattern: … | +| `ARCHIVE_EXTRACTION_FAILED` | 53011 | Failed to extract archive: … | +| `ARCHIVE_UNSUPPORTED_TYPE` | 53012 | Unsupported archive type: … | +| `ARCHIVE_MISSING_SHARDS` | 53013 | Archive is missing required shard file: … | +| `PARTIAL_DOWNLOAD_OFFLINE` | 53014 | Cannot resume partial download (… bytes downloaded) - unable to connect. URL: … | +| `REGISTRY_DOWNLOAD_FAILED` | 53015 | Registry download failed: … | +| `DELETE_CACHE_FAILED` | 53200 | Failed to delete cache… | +| `INVALID_DELETE_CACHE_PARAMS` | 53201 | Invalid deleteCache parameters - provide either modelId or cacheKey | +| `CACHE_DIR_NOT_ABSOLUTE` | 53202 | Cache directory must be an absolute path | +| `CACHE_DIR_NOT_WRITABLE` | 53203 | Cache directory is not writable: …… | +| `SET_CONFIG_FAILED` | 53350 | Failed to set config… | +| `CONFIG_ALREADY_SET` | 53351 | Config has already been set and is immutable. Config can only be set once during SDK initialization. | +| `FFMPEG_NOT_AVAILABLE` | 53500 | FFmpeg is not available on this system | +| `AUDIO_PLAYER_FAILED` | 53501 | Audio player failed: … | +| `INVALID_AUDIO_CHUNK_TYPE` | 53502 | Invalid audio chunk type | +| `DELEGATE_NO_FINAL_RESPONSE` | 53700 | No final response received from delegated provider | +| `DELEGATE_CONNECTION_FAILED` | 53701 | Failed to connect to delegated provider: … | +| `DELEGATE_PROVIDER_ERROR` | 53702 | Delegated provider error: … | +| `RPC_NO_DATA_RECEIVED` | 53703 | No data received from request | +| `RPC_UNKNOWN_REQUEST_TYPE` | 53704 | Unknown request type received: … | +| `PLUGIN_NOT_FOUND` | 53850 | Plugin not found for model type "…". If using a custom worker bundle, ensure the plugin is included in your qvac.config plugins array and rebuild with "npx qvac bundle sdk". | +| `PLUGIN_HANDLER_NOT_FOUND` | 53851 | Handler "…" not found in plugin "…" | +| `PLUGIN_REQUEST_VALIDATION_FAILED` | 53852 | Request validation failed for handler "…"… | +| `PLUGIN_RESPONSE_VALIDATION_FAILED` | 53853 | Response validation failed for handler "…"… | +| `PLUGIN_ALREADY_REGISTERED` | 53854 | Plugin already registered for modelType: … | +| `PLUGIN_HANDLER_TYPE_MISMATCH` | 53855 | Handler "…" is …, but was called as …. Use invokePlugin() for reply handlers and invokePluginStream() for streaming handlers. | +| `PLUGIN_LOGGING_INVALID` | 53856 | Plugin "…" has invalid logging configuration: … | +| `PLUGIN_DEFINITION_INVALID` | 53857 | Plugin definition invalid for "…": … | +| `PLUGIN_MODEL_TYPE_RESERVED` | 53858 | modelType "…" is reserved for built-in plugins | +| `PLUGIN_LOAD_CONFIG_VALIDATION_FAILED` | 53859 | modelConfig validation failed for "…": … | +| `LIFECYCLE_SUSPEND_FAILED` | 53600 | Runtime suspend failed… | +| `LIFECYCLE_RESUME_FAILED` | 53601 | Runtime resume failed… | +| `LIFECYCLE_OPERATION_BLOCKED` | 53602 | Operation "…" is blocked while runtime state is "…" | +| `PATH_TRAVERSAL` | 53900 | Path traversal detected: "…" escapes base directory "…" | +| `QVAC_MODEL_REGISTRY_QUERY_FAILED` | 53950 | QVAC model registry query failed… | diff --git a/docs/website/content/docs/sdk/release-notes/index.mdx b/docs/website/content/docs/sdk/release-notes/index.mdx index 9a1c3c796d..6a176bf6c9 100644 --- a/docs/website/content/docs/sdk/release-notes/index.mdx +++ b/docs/website/content/docs/sdk/release-notes/index.mdx @@ -1,221 +1,454 @@ --- -title: SDK Release Notes — v0.9.1 +title: SDK Release Notes — v0.10.0 description: QVAC SDK release notes -schemaType: TechArticle --- -📦 **NPM:** https://www.npmjs.com/package/@qvac/sdk/v/0.9.1 +📦 **NPM:** https://www.npmjs.com/package/@qvac/sdk/v/0.10.0 -Patch release with a minor documentation fix to the SDK README quickstart example — no API, behavioral, or model changes. +This release lands a redesigned completion API built on a unified event stream, a generic +companion-set system that handles multi-file models in parallel, and a much stronger model +type/capability system that catches mis-routed calls at compile time. It also rewires +delegated inference to direct DHT connections, expands the addon surface (img2img, +structured output, dynamic tools, tool dialects, per-segment whisper metadata, +sentence-streaming TTS), and reshapes the model registry around companion sets. -📦 **NPM:** https://www.npmjs.com/package/@qvac/sdk/v/0.9.0 +## Breaking Changes -This release significantly expands the SDK's capabilities with finetuning support, image generation via Stable Diffusion, duplex streaming transcription, and a suspend/resume lifecycle for mobile apps. Delegation gets healthier with heartbeat probes and remote cancellation. Tool-calling completions are now more robust with KV cache fixes, and a new profiler gives deep visibility into operation performance. React Native compatibility improves with Buffer-free diffusion and better progress event handling. +### @qvac/sdk -## Breaking Changes +### Unified `CompletionEvent` stream + +`completion()` now returns a `CompletionRun` with a single canonical `events` stream that +carries content, thinking, tool calls, stats, and completion in one ordered, sequenced +sequence. The legacy `tokenStream`/`stats` fields still work as derived views, but the +event stream is the authoritative API going forward and is what enables features like +captured thinking and structured tool framing. + +**Before:** + +```typescript +const result = completion({ modelId, history, stream: true }); +for await (const token of result.tokenStream) { /* ... */ } +const stats = await result.stats; +``` + +**After:** + +```typescript +const run = completion({ modelId, history, stream: true, captureThinking: true }); +for await (const event of run.events) { + if (event.type === "contentDelta") process.stdout.write(event.text); + if (event.type === "toolCall") console.log(event.call.name); +} +const result = await run.final; +// result.contentText, result.thinkingText, result.toolCalls, result.stats, result.raw.fullText +``` -### @qvac/sdk (v0.9.0) +### Model type & capability system overhaul -### `ping()` Replaced by `heartbeat()` +`LoadModelOptions` is no longer a single catch-all. Custom plugins must use the new +`LoadCustomPluginModelOptions<"plugin-name">` generic so the literal plugin string is +pinned at the type level. Built-in model types continue to pick the right overload +automatically when the annotation is dropped. -The `ping()` API has been replaced by `heartbeat()`, which supports both local and delegated (P2P) health checks. This enables proactive provider status monitoring before and during delegated inference. +At runtime, built-in SDK operations now throw `MODEL_OPERATION_NOT_SUPPORTED` when called +against the wrong model type — with a message that lists the requested operation, the +loaded model's type, and the supported operations on it. The lower-level `pluginInvoke` +and `pluginInvokeStream` paths still surface `PLUGIN_HANDLER_NOT_FOUND` as before. + +`translate(...)` now routes by the loaded model's registered type. Passing a mismatched +`modelType` throws `ModelTypeMismatchError` instead of silently mis-routing the call. **Before:** ```typescript -import { ping } from "@qvac/sdk"; -const pong = await ping(); +import type { LoadModelOptions } from "@qvac/sdk"; + +const opts: LoadModelOptions = { + modelSrc: "/path/foo", + modelType: "my-custom-plugin", + modelConfig: { whatever: 1 }, +}; +await loadModel(opts); ``` **After:** ```typescript -import { heartbeat } from "@qvac/sdk"; +import type { LoadCustomPluginModelOptions } from "@qvac/sdk"; + +const opts: LoadCustomPluginModelOptions<"my-custom-plugin"> = { + modelSrc: "/path/foo", + modelType: "my-custom-plugin", + modelConfig: { whatever: 1 }, +}; +await loadModel(opts); +// Or just drop the annotation — TS picks the right overload. +``` -// Local heartbeat (replaces ping) -await heartbeat(); +```typescript +import { SDK_SERVER_ERROR_CODES } from "@qvac/sdk"; + +try { + await transcribe({ modelId: llmModelId /* ... */ }); +} catch (e) { + if ((e as { code?: number })?.code === SDK_SERVER_ERROR_CODES.MODEL_OPERATION_NOT_SUPPORTED) { + // Includes requested operation, loaded model type, supported operations, + // and suggested model types. + } +} +``` -// Delegated heartbeat — check if a remote provider is alive -await heartbeat({ - delegate: { topic: "topicHex", providerPublicKey: "peerHex", timeout: 3000 }, -}); +### Companion-set download progress field + +Multi-file model downloads (ONNX, future formats) now report progress through a generic +`fileSetInfo` field instead of the ONNX-specific `onnxInfo`. The shape is identical, only +the field name changed. + +**Before:** + +```typescript +onProgress: (progress) => { + if (progress.onnxInfo) { + console.log(`[${progress.onnxInfo.currentFile}] ${progress.onnxInfo.overallPercentage.toFixed(1)}%`); + } +} ``` -## Features +**After:** + +```typescript +onProgress: (progress) => { + if (progress.fileSetInfo) { + console.log(`[${progress.fileSetInfo.currentFile}] ${progress.fileSetInfo.overallPercentage.toFixed(1)}%`); + } +} +``` + +### Delegated inference uses direct DHT connect -### @qvac/sdk (v0.9.0) +Delegation no longer rendezvous over a shared topic. Consumers connect directly to a +provider's public key via `swarm.dht.connect(publicKey)`, and providers bind the DHT +server with `swarm.listen()` instead of announcing a topic. This removes a class of +discovery-flake failures and shortens connect time. Callers using the high-level +delegation API see no surface change; integrators driving Hyperswarm directly should +update their join/listen logic. -### Finetuning +### Plugin constructor migration -The SDK now supports LoRA finetuning of loaded LLM models. Training runs can be started, paused, resumed, cancelled, and inspected — all through a single `finetune()` function. Progress streams provide real-time loss and step metrics. +SDK plugins (`definePlugin`) now use the new addon constructor shape. Plugin authors +need to migrate their `createModel` implementation to match — the SDK in this release +ships with all first-party plugins already migrated. + +## New APIs and Capabilities + +### `getLoadedModelInfo` for runtime introspection + +A new `getLoadedModelInfo` API returns metadata for a loaded `modelId`, discriminated on +`isDelegated`. Local models expose their authoritative handler list and `modelType`; +delegated models defer to the provider. Useful for preflighting a built-in SDK call +before issuing the RPC. ```typescript -import { finetune } from "@qvac/sdk"; +import { getLoadedModelInfo, transcribe } from "@qvac/sdk"; + +const info = await getLoadedModelInfo({ modelId }); + +if (info.isDelegated || info.handlers.includes("transcribeStream")) { + await transcribe({ modelId /* ... */ }); +} +``` + +### Structured output (`responseFormat`) -const handle = finetune({ +`completion()` now accepts a `responseFormat` option that constrains the model to emit +schema-valid JSON. The output is guaranteed to parse against the supplied JSON Schema. + +```typescript +const run = completion({ modelId, - options: { - trainDatasetDir: "./dataset/train", - validation: { type: "dataset", path: "./dataset/eval" }, - outputParametersDir: "./artifacts/lora", - numberOfEpochs: 2, + history: [{ role: "user", content: "Extract: I'm Alice, 30, data engineer." }], + stream: true, + responseFormat: { + type: "json_schema", + json_schema: { + name: "Person", + schema: { + type: "object", + properties: { + name: { type: "string" }, + age: { type: "integer" }, + occupation: { type: "string" }, + }, + required: ["name", "age", "occupation"], + additionalProperties: false, + }, + }, }, }); -for await (const progress of handle.progressStream) { - console.log(progress.global_steps, progress.loss); +for await (const event of run.events) { + if (event.type === "contentDelta") process.stdout.write(event.text); } -const result = await handle.result; +const final = await run.final; +JSON.parse(final.contentText); // schema-valid ``` -Operations: `start`, `resume`, `pause`, `cancel`, `getState`. Omit `operation` to let the addon auto-detect whether to start fresh or resume. +### Dynamic tools mode -### Image Generation (Diffusion) - -Stable Diffusion models are now integrated as a first-class SDK capability. Load a diffusion model and generate images with step-by-step progress tracking. +LLM models can now opt into a `dynamic` tools mode at load time. Subsequent +`completion()` calls can pass an entirely different `tools` array on each turn, and the +addon trims the previous tool block from the KV cache so rotation is free — no need to +invalidate the cache or pin the tool set per-session. ```typescript -import { loadModel, diffusion, SD_V2_1_1B_Q8_0 } from "@qvac/sdk"; +import { loadModel, completion, TOOLS_MODE, QWEN3_1_7B_INST_Q4 } from "@qvac/sdk"; const modelId = await loadModel({ - modelSrc: SD_V2_1_1B_Q8_0, - modelType: "diffusion", - modelConfig: { prediction: "v" }, + modelSrc: QWEN3_1_7B_INST_Q4, + modelType: "llm", + modelConfig: { + ctx_size: 4096, + tools: true, + toolsMode: TOOLS_MODE.dynamic, + }, }); -const { progressStream, outputs, stats } = diffusion({ - modelId, - prompt: "a cat sitting on a windowsill", - width: 512, - height: 512, - steps: 20, +// Turn 1 — weather tools. +const turn1 = completion({ + modelId, history, kvCache, stream: true, + tools: [{ name: "get_weather", description: "...", parameters: weatherSchema }], }); -for await (const { step, totalSteps } of progressStream) { - console.log(`${step}/${totalSteps}`); -} -const buffers = await outputs; +// Turn 2 — same kvCache, different tools. Free rotation. +const turn2 = completion({ + modelId, history, kvCache, stream: true, + tools: [{ name: "get_horoscope", description: "...", parameters: horoscopeSchema }], +}); ``` -### Duplex Streaming Transcription (`transcribeStream`) +### Tool-call dialect routing -A new bidirectional streaming API lets you feed audio incrementally and receive transcription segments as speech is detected, enabling real-time voice interfaces. +Tool-call parsing is now dialect-aware. The SDK auto-detects between `hermes`, +`pythonic`, and `json` framings, and a new `toolDialect` parameter lets you force a +specific parser when auto-detection picks the wrong path — common for Llama 3.x +fine-tunes that emit native pythonic headers, which the auto-router defaults to `hermes` +for empirical reasons. ```typescript -import { transcribeStream } from "@qvac/sdk"; +import { completion, type ToolDialect } from "@qvac/sdk"; -const session = await transcribeStream({ modelId }); -session.write(audioChunk); -session.end(); - -for await (const text of session) { - console.log(text); -} -session.destroy(); +const result = completion({ + modelId, history, tools, stream: true, + toolDialect: "pythonic", // "hermes" | "pythonic" | "json" +}); ``` -The previous single-shot `transcribeStream({ modelId, audioChunk })` pattern still works but logs a deprecation warning — use `transcribe()` for batch transcription. +### img2img for diffusion models + +The diffusion API now accepts an `init_image` for SDEdit-style image-to-image on +SD/SDXL, and in-context conditioning on FLUX.2. `strength` controls how much of the +source is preserved on SD/SDXL; FLUX.2 ignores it (the path is purely conditional). + +```typescript +const initImage = new Uint8Array(fs.readFileSync("input.png")); +const { outputs } = diffusion({ + modelId, + prompt: "oil painting style, vibrant colors", + init_image: initImage, + strength: 0.5, // 0 = keep source, 1 = ignore source +}); +``` -### Suspend/Resume Lifecycle +### Sentence-level TTS streaming -Mobile and desktop apps can now cleanly suspend and resume SDK operations when the app enters the background or foreground, preventing resource leaks and stale state. +Onnx text-to-speech can now stream output one sentence at a time, either as a +self-contained `textToSpeech({ stream: true, sentenceStream: true })` call or via a +duplex `textToSpeechStream` session that you can pipe a streaming LLM into. Each chunk +exposes the int16 PCM samples plus the source sentence and chunk index. ```typescript -import { suspend, resume } from "@qvac/sdk"; +const session = await textToSpeechStream({ + modelId: ttsModelId, + inputType: "text", + accumulateSentences: true, + sentenceDelimiterPreset: "latin", // "latin" | "cjk" | "multilingual" + flushAfterMs: 400, +}); + +(async () => { + for await (const delta of completion({ modelId: llmModelId /* ... */ }).tokenStream) { + session.write(delta); + } + session.end(); +})(); -await suspend(); // app going to background -await resume(); // app returning to foreground +for await (const chunk of session) { + // chunk.buffer / chunk.chunkIndex / chunk.sentenceChunk + if (chunk.done) break; +} ``` -### Delegated Cancellation +### Per-segment whisper metadata -Remote inference and downloads running on a delegation provider can now be cancelled from the consumer side. +Both `transcribe` (batch) and `transcribeStream` (duplex) now return structured +`TranscribeSegment` objects with start/end timestamps, segment IDs, and an `append` +flag — enabling proper subtitle generation and timeline alignment instead of raw text +concatenation. ```typescript -import { cancel } from "@qvac/sdk"; +const segments = await transcribe({ modelId, audioChunk: audioFilePath, metadata: true }); +for (const s of segments) { + console.log(`[${s.startMs}ms → ${s.endMs}ms] id=${s.id} append=${s.append} ${s.text}`); +} +``` -await cancel({ operation: "inference", modelId: "delegated-model-id" }); +### Suspend lifecycle gate and `state()` -await cancel({ - operation: "downloadAsset", - downloadKey: "download-key", - delegate: { topic: "topicHex", providerPublicKey: "peerHex" }, -}); +`suspend()` is now serialized through a lifecycle gate that prevents overlapping +suspend/resume races. A new `state()` API reports the current lifecycle phase: +`active`, `suspending`, `suspended`, or `resuming`. + +```typescript +import { state, suspend, resume, type LifecycleState } from "@qvac/sdk"; + +await suspend(); +const current: LifecycleState = await state(); +if (current !== "active") { + await resume(); +} ``` -### Delegation Health Check Timeout +### Registry download retries and configurable stream timeout -A new `healthCheckTimeout` option on the delegate config lets you control how long the RPC health probe waits before marking a cached connection as stale and reconnecting. +Two new SDK config knobs cover slow/unstable links: `registryDownloadMaxRetries` retries +`REQUEST_TIMEOUT` failures (set to `0` to disable), and `registryStreamTimeoutMs` +extends the per-block stream timeout beyond the default 60s. ```typescript -await loadModel({ - modelSrc: LLAMA_3_2_1B_INST_Q4_0, - modelType: "llm", - delegate: { - topic: topicHex, - providerPublicKey, - timeout: 30_000, - healthCheckTimeout: 2000, - }, +import { setSDKConfig } from "@qvac/sdk"; + +setSDKConfig({ + registryDownloadMaxRetries: 5, + registryStreamTimeoutMs: 180_000, }); ``` -### Addon Stats Across All Operations +### Auto KV-cache: replay the canonical assistant turn -All inference operations now return detailed performance stats from the underlying addons. Completion, transcription, translation, TTS, and embedding responses all include stats like `tokensPerSecond`, `timeToFirstToken`, `audioDuration`, and the new `backendDevice` field (`"cpu"` or `"gpu"`). +When auto KV-cache is enabled, the completion result now exposes +`final.cacheableAssistantContent` — the exact assistant string the SDK persisted to the +cache key on this turn. Push it back into `history` verbatim on the next turn to +guarantee a cache hit. Tool-call turns aren't auto-cached today and omit the field; +fall back to `final.contentText` in that case. ```typescript -const { embedding, stats } = await embed({ modelId, text: "hello" }); -console.log(stats?.backendDevice); // "cpu" | "gpu" +const run = completion({ modelId, history, kvCache: true }); +for await (const _ of run.tokenStream) { /* stream */ } +const final = await run.final; +const nextHistory = [ + ...history, + { role: "assistant", content: final.cacheableAssistantContent ?? final.contentText }, + { role: "user", content: "follow-up question" }, +]; ``` -### @qvac/sdk (v0.9.0) +### LLM-addon cache API plumbed through SDK -- **CLD2 language detection** is now integrated into the SDK for automatic language identification. -- **OCR plugin updated** to work with `@qvac/ocr-onnx@0.4.0`. -- **TTS interface refactored** — the TTS package uses a new `files`-based constructor with absolute paths, replacing the legacy loader pattern. +The SDK now wires through the LLM addon's first-class cache API — including explicit +`deleteCache({ kvCacheKey })` for evicting a named cache key — so consumers can manage +KV-cache lifetimes alongside `loadModel`/`unloadModel`. -## Bug Fixes +### NMTcpp 2.0.1 surface -### @qvac/sdk (v0.9.0) - -- **KV cache preserved across tool-call round-trips** — multi-turn tool-calling completions no longer lose context between rounds. -- **KV cache save race condition** fixed in tool-calling completions — concurrent saves no longer corrupt the cache. -- **`` blocks stripped** before parsing tool calls — reasoning traces from models like DeepSeek no longer break tool call extraction. -- **Progress event buffering** — throttled progress events are now buffered instead of dropped, ensuring no updates are lost during fast download sequences. -- **RPC progress throttling** — progress frames are throttled to prevent `Maximum call stack size exceeded` errors during high-frequency updates. -- **Clean process exit** — the Bare runtime process global is now handled correctly, and RPC close triggers a clean exit. -- **Connection teardown race** in `closeConnections` resolved — concurrent teardowns no longer deadlock. -- **React Native diffusion compatibility** — `Buffer` replaced with `Uint8Array` in the diffusion client, fixing React Native builds. -- **Download progress accuracy** — registry downloads now use network-layer progress instead of disk I/O measurements. -- **VLM addon classification** — the model registry was regenerated to fix incorrect VLM addon type assignments. -- **ONNX companion files** — `.onnx.data` companion files are now correctly resolved during registry model resolution. -- **Security hardening** — multiple code scanning alerts resolved across SDK pod packages. +The SDK NMT plugin now targets `@qvac/translation-nmtcpp 2.0.1` with a structured +constructor that distinguishes primary and pivot model files, vocab files, and pivot +config (beam size, top-k). Bergamot models are also picked up via path-based vocab +resolution and grouped into companion sets, which lets the cache and download paths +treat them like any other multi-file model. ---- +## Features -## 📦 Model Changes +### @qvac/sdk -Model registry updated: 312 → 653 (+341). See [model changes](./changelog/0.9.0/models.md) for the full list. +### Parallel orchestration and download dedupe -- **295 Bergamot translation models** — offline NMT covering 42 language pairs bidirectional (az, be, bg, bn, bs, ca, da, de, el, et, fa, fi, gu, he, hi, hr, hu, id, is, kn, ko, lt, lv, ml, ms, mt, nb, nl, nn, pl, ro, sk, sl, sq, sr, sv, ta, te, tr, uk, vi). Each pair includes model weights, lexical shortlists, vocabularies, and metadata. -- **5 FLUX models** — FLUX.2 Klein 4B in Q4_0, Q4_K_M, Q6_K, Q8_0 quantizations plus VAE. -- **4 Stable Diffusion models** — SD v2.1 1B (Q4_0, Q8_0) and SDXL Base 1.0 3B (Q4_0, Q8_0). -- **17 TTS Supertonic models** — Official Supertone FP32 variants including duration predictor, text encoder, vocoder, config, unicode indexer, and 10 voice styles. -- **1 LLM model** — Qwen3 4B (Q4_K_M). +Model loading is now genuinely parallel where it can be: the primary model and any +companion files (vision projection, vocab, etc.) download concurrently, and concurrent +requests for the same asset are deduplicated to a single transfer. Cancellation cleans +up all active transfers atomically with no leaked state. Profiling fields +(`sourceType`, `cacheHit`, `sharedTransfer`, `totalLoadTime`, +`modelInitializationTime`, `checksumValidationTime`) are populated correctly across +both primary and companion downloads, with aggregate stats merged at the run level. ---- +The companion pipeline is also generic: `companions.ts` is the only format-aware piece, +and adding a new multi-file format is a matter of dropping in a detection function and +registering it with `groupCompanionSets`. Everything downstream — codegen, resolver, +cache probing, storage cleanup — handles it automatically. + +### Real-time voice assistant example -## 🧹 Other Changes +A new end-to-end example demonstrates a real-time voice assistant pipeline (whisper → +LLM → TTS) wired together using the SDK's streaming primitives. -- Updated addon dependencies: `@qvac/tts-onnx` to v0.6.7, `@qvac/transcription-whispercpp` to latest, Parakeet to v0.2.7, `@qvac/diffusion-cpp` to ^0.1.3. -- Replaced FeatureBase support links with Discord channel. -- Bumped `bare-crypto` and `@qvac/rag` for runtime stability. -- Renamed `@tetherto` npm references to `@qvac` namespace across READMEs. -- Improved test infrastructure with SDK test bootstrap and CI model caching. +## Added -## Documentation +### @qvac/sdk -### @qvac/sdk (v0.9.1) +``` +NMT_Q0F16 through NMT_Q0F16_9 (10 entries) +NMT_Q4_0 through NMT_Q4_0_12+ (22 entries) +``` + +### Removed (now companion-only or renamed) + +``` +*_DATA (32 entries — companion-only, e.g. PARAKEET_TDT_ENCODER_DATA_FP32, TTS_*_DATA) +BERGAMOT_*_LEX (93 entries — companion-only) +BERGAMOT_*_VOCAB (93 entries — companion-only) +BERGAMOT_METADATA_* (87 entries — companion-only) +MARIAN_OPUS_* (32 entries — renamed to NMT_*) +``` + +## Documentation, Tests, and Infrastructure + +- Diffusion documentation was extended to cover the new img2img flows (SDEdit on + SD/SDXL, in-context conditioning on FLUX.2). +- Android sharded-model-resume tests no longer trip Scudo OOM — the test harness now + bounds memory more conservatively on long-running resume scenarios. +- The tests-qvac docs, tooling, and CI workflow job names were refreshed for the new + suite filtering and PR-triggered e2e workflows. Suite filtering plus PR-trigger labels + let CI run targeted SDK e2e subsets on demand instead of always running the full grid. +- A pre-terminate cleanup hook stabilises mobile smoke: the mobile auto-close path now + awaits worker cleanup acknowledgement before terminating the worklet. +- `DataLoader` cleanup logic was scoped down to `packages/rag` so the SDK no longer + carries that surface. + +## Bug Fixes -- Remove trailing comma in quickstart import example. +### @qvac/sdk + +- RPC initialization in the Node runtime now has an explicit timeout, so a wedged + transport can no longer hang `loadModel`/`unloadModel` indefinitely. +- The registry client now opens its corestore with `wait: true`, eliminating a startup + race where downloads could begin before replication was ready. +- KV-cache `savedCount` is no longer incremented on cancelled or zero-token turns, + preventing inflated cache stats. +- `delete-cache` RPC now scopes invalidation to the deleted key only instead of wiping + unrelated entries. +- Delegated transports strip the `__profiling` envelope before zod validation, fixing a + spurious validation error when profiling is enabled on the consumer side. +- Replaced `z.xor` with `z.union` and bumped the zod floor to `^4.3.0` to track upstream + breaking changes. +- LLM-based translation now uses deterministic decoding so the same input produces the + same output across runs. +- Inflight delegation requests that get rejected now run their cleanup chain to + completion instead of leaking pending promises. + +## Model Registry Changes + +The model registry was regenerated around companion-set metadata. The user-facing surface +is leaner: families that used to live as separate `*_DATA`, `*_LEX`, `*_VOCAB`, and +`METADATA_*` constants are now companion-only — they're still downloaded, but they're +not addressable as standalone model sources. Marian Opus models were renamed under the +`NMT_*` namespace to match the rest of the NMT family. diff --git a/docs/website/content/docs/sdk/release-notes/v0.9.0.mdx b/docs/website/content/docs/sdk/release-notes/v0.9.1.mdx similarity index 95% rename from docs/website/content/docs/sdk/release-notes/v0.9.0.mdx rename to docs/website/content/docs/sdk/release-notes/v0.9.1.mdx index 15b553769a..9a1c3c796d 100644 --- a/docs/website/content/docs/sdk/release-notes/v0.9.0.mdx +++ b/docs/website/content/docs/sdk/release-notes/v0.9.1.mdx @@ -1,16 +1,20 @@ --- -title: SDK Release Notes — v0.9.0 +title: SDK Release Notes — v0.9.1 description: QVAC SDK release notes schemaType: TechArticle --- +📦 **NPM:** https://www.npmjs.com/package/@qvac/sdk/v/0.9.1 + +Patch release with a minor documentation fix to the SDK README quickstart example — no API, behavioral, or model changes. + 📦 **NPM:** https://www.npmjs.com/package/@qvac/sdk/v/0.9.0 This release significantly expands the SDK's capabilities with finetuning support, image generation via Stable Diffusion, duplex streaming transcription, and a suspend/resume lifecycle for mobile apps. Delegation gets healthier with heartbeat probes and remote cancellation. Tool-calling completions are now more robust with KV cache fixes, and a new profiler gives deep visibility into operation performance. React Native compatibility improves with Buffer-free diffusion and better progress event handling. ## Breaking Changes -### @qvac/sdk +### @qvac/sdk (v0.9.0) ### `ping()` Replaced by `heartbeat()` @@ -39,7 +43,7 @@ await heartbeat({ ## Features -### @qvac/sdk +### @qvac/sdk (v0.9.0) ### Finetuning @@ -165,7 +169,7 @@ const { embedding, stats } = await embed({ modelId, text: "hello" }); console.log(stats?.backendDevice); // "cpu" | "gpu" ``` -### @qvac/sdk +### @qvac/sdk (v0.9.0) - **CLD2 language detection** is now integrated into the SDK for automatic language identification. - **OCR plugin updated** to work with `@qvac/ocr-onnx@0.4.0`. @@ -173,7 +177,7 @@ console.log(stats?.backendDevice); // "cpu" | "gpu" ## Bug Fixes -### @qvac/sdk +### @qvac/sdk (v0.9.0) - **KV cache preserved across tool-call round-trips** — multi-turn tool-calling completions no longer lose context between rounds. - **KV cache save race condition** fixed in tool-calling completions — concurrent saves no longer corrupt the cache. @@ -209,3 +213,9 @@ Model registry updated: 312 → 653 (+341). See [model changes](./changelog/0.9. - Bumped `bare-crypto` and `@qvac/rag` for runtime stability. - Renamed `@tetherto` npm references to `@qvac` namespace across READMEs. - Improved test infrastructure with SDK test bootstrap and CI model caching. + +## Documentation + +### @qvac/sdk (v0.9.1) + +- Remove trailing comma in quickstart import example. diff --git a/docs/website/package-lock.json b/docs/website/package-lock.json index 54d57ee670..3af7f01cd4 100644 --- a/docs/website/package-lock.json +++ b/docs/website/package-lock.json @@ -47,6 +47,7 @@ "@types/react": "^19.1.13", "@types/react-dom": "^19.1.9", "@vahor/next-broken-links": "^0.4.1", + "bun": "^1.3.11", "glob": "^11.0.3", "nunjucks": "^3.2.4", "postcss": "^8.5.6", @@ -60,6 +61,7 @@ "typedoc": "^0.28.17", "typedoc-plugin-frontmatter": "^1.3.1", "typedoc-plugin-markdown": "^4.10.0", + "typedoc-plugin-zod": "^1.4.3", "typescript": "^5.9.2", "unified": "^11.0.2", "unist-util-visit": "^5.0.0", @@ -2739,6 +2741,174 @@ "node": ">= 20.0.0" } }, + "node_modules/@oven/bun-darwin-aarch64": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-darwin-aarch64/-/bun-darwin-aarch64-1.3.13.tgz", + "integrity": "sha512-qAS6Hg8Q14ckfBuqJ2Zh7gBQSVSUHeibSq4OFqBTv6DzyJuxYlr0sdYQzmYmnbPxbqobekqUDTa/4XEaqRi7vg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-darwin-x64": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-darwin-x64/-/bun-darwin-x64-1.3.13.tgz", + "integrity": "sha512-kGePeDD4IN4imo+H4uLjQGZLmvyYQg+nKr2P0nt4ksXXrWA4HE+mb0/TUPHfRI127DocXQpew+fvrHuHR5mpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-darwin-x64-baseline": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-darwin-x64-baseline/-/bun-darwin-x64-baseline-1.3.13.tgz", + "integrity": "sha512-gMEQayUpmCPYaE9zkNBj9TiQqHupnhjOYcuSzxFjzIjHJBUO4VjNnrpbKVeXNs+rKHFothORDd2QKquu5paSPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-linux-aarch64": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-aarch64/-/bun-linux-aarch64-1.3.13.tgz", + "integrity": "sha512-NbLOJdr+RBFO1vFZ2YUFg4oVJ+2ua6zrwo4ZWRs0jKKcGJWtbY2wY5uz+i0PkwH6b9HYaYDgVTzE4ev06ncYZw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-aarch64-musl": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-aarch64-musl/-/bun-linux-aarch64-musl-1.3.13.tgz", + "integrity": "sha512-UV9EE18VE5aRhWtV2L6MTAGGn3slhJJ2OW/m+FJM15maHm0qf1V7TaZY0FovxhdQRvnklSiQ7Ntv0H5TUX4w0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64/-/bun-linux-x64-1.3.13.tgz", + "integrity": "sha512-UwttIUXoe9fS+40OcjoaRHgZw+HCPFqBVWEXkXqAJ3W7wA0XPZrWsoMAD9sGh3TaLqrwdiMo5xPogwpXhOtVXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-baseline": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-baseline/-/bun-linux-x64-baseline-1.3.13.tgz", + "integrity": "sha512-fOi4ziKzgJG4UrrNd4AicBs6Fu9GY5xOqg+9tC76nuZNDAdSh6++kzab6TNi1Ck0Yzq6zIBIdGit6/0uSbBn8A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-musl": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-musl/-/bun-linux-x64-musl-1.3.13.tgz", + "integrity": "sha512-+VHhE44kEjCXcTFHyc81zfTxL9+vzh9RqIh7gM1iWNhxpctD9kzntbUkP3UTFTwwNjoou1o8VRyxQafvc4OepA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-musl-baseline": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-musl-baseline/-/bun-linux-x64-musl-baseline-1.3.13.tgz", + "integrity": "sha512-fqBKuiiWLEu2dVkowZaXgKS98xfrvBqivdoxRtRP3eINcpI1dcelGbsOz+Xphn7tbGAuBiE1/0AelvvvdqS9rg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-windows-aarch64": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-windows-aarch64/-/bun-windows-aarch64-1.3.13.tgz", + "integrity": "sha512-+EvdRWRCRg95Xea4M2lqSJFTjzQBTJDQTMlbG8bmwFkVTN16MdmSH7xhfxVQWUOyZBLEpIwuNFIlBBxVCwSUyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oven/bun-windows-x64": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-windows-x64/-/bun-windows-x64-1.3.13.tgz", + "integrity": "sha512-vqDEFX63ZZQF3YstPSpPD+RxNm5AILPdUuuKpNwsj7ld4NjhdHUYkAmLXDtKNWt9JMRL10bop//W8faY/LV+RQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oven/bun-windows-x64-baseline": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-windows-x64-baseline/-/bun-windows-x64-baseline-1.3.13.tgz", + "integrity": "sha512-6gy4hhQSjq/T/S9hC9m3NxY0RY+9Ww+XNlB+8koIMTsMSYEjk7Ho+hFHQz1Bn4W61Ub7Vykufg+jgDgPfa2GFA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -4328,7 +4498,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4342,7 +4511,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4356,7 +4524,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4370,7 +4537,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4384,7 +4550,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4398,7 +4563,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4412,7 +4576,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4426,7 +4589,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4440,7 +4602,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4454,7 +4615,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4468,7 +4628,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4482,7 +4641,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4496,7 +4654,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4510,7 +4667,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4524,7 +4680,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4538,7 +4693,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4552,7 +4706,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4566,7 +4719,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4580,7 +4732,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4594,7 +4745,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4608,7 +4758,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4622,7 +4771,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4636,7 +4784,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4650,7 +4797,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4664,7 +4810,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5523,7 +5668,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -5534,7 +5678,6 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -5829,7 +5972,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5980,35 +6122,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -6113,20 +6226,6 @@ "baseline-browser-mapping": "dist/cli.js" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/boxen": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", @@ -6160,20 +6259,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -6181,6 +6266,41 @@ "dev": true, "license": "MIT" }, + "node_modules/bun": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/bun/-/bun-1.3.13.tgz", + "integrity": "sha512-b9T4xZ8KqCHs4+TkHJv540LG1B8OD7noKu0Qaizusx3jFtMDHY6osNqgbaOlwW2B8RB2AKzz+sjzlGKIGxIjZw==", + "cpu": [ + "arm64", + "x64" + ], + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "os": [ + "darwin", + "linux", + "win32" + ], + "bin": { + "bun": "bin/bun.exe", + "bunx": "bin/bunx.exe" + }, + "optionalDependencies": { + "@oven/bun-darwin-aarch64": "1.3.13", + "@oven/bun-darwin-x64": "1.3.13", + "@oven/bun-darwin-x64-baseline": "1.3.13", + "@oven/bun-linux-aarch64": "1.3.13", + "@oven/bun-linux-aarch64-musl": "1.3.13", + "@oven/bun-linux-x64": "1.3.13", + "@oven/bun-linux-x64-baseline": "1.3.13", + "@oven/bun-linux-x64-musl": "1.3.13", + "@oven/bun-linux-x64-musl-baseline": "1.3.13", + "@oven/bun-windows-aarch64": "1.3.13", + "@oven/bun-windows-x64": "1.3.13", + "@oven/bun-windows-x64-baseline": "1.3.13" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -6571,7 +6691,6 @@ "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=20" } @@ -6743,7 +6862,6 @@ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10" } @@ -7153,7 +7271,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -7824,20 +7941,6 @@ } } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -7894,7 +7997,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -7910,7 +8012,6 @@ "resolved": "https://registry.npmjs.org/fumadocs-core/-/fumadocs-core-16.3.2.tgz", "integrity": "sha512-lpvW2qnH0C7c1CGCv6Ym1GrDTVyV+APb1h3hBuWcGiAamNN1vw7lldXQVJ5ENL/SJr6TQ6gJ+qHExNohsh/ynA==", "license": "MIT", - "peer": true, "dependencies": { "@formatjs/intl-localematcher": "^0.7.2", "@orama/orama": "^3.1.17", @@ -8214,20 +8315,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -8751,20 +8838,6 @@ "dev": true, "license": "MIT" }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-buffer": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", @@ -8822,17 +8895,6 @@ "dev": true, "license": "MIT" }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -8843,20 +8905,6 @@ "node": ">=8" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-hexadecimal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", @@ -8880,17 +8928,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -8994,7 +9031,7 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -9107,7 +9144,7 @@ "version": "1.30.2", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", - "dev": true, + "devOptional": true, "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -9140,7 +9177,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9161,7 +9197,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9182,7 +9217,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9203,7 +9237,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9224,7 +9257,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9245,7 +9277,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9266,7 +9297,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9287,7 +9317,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9308,7 +9337,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9329,7 +9357,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9350,7 +9377,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9478,7 +9504,6 @@ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.562.0.tgz", "integrity": "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==", "license": "ISC", - "peer": true, "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } @@ -10813,7 +10838,6 @@ "resolved": "https://registry.npmjs.org/next/-/next-16.1.1.tgz", "integrity": "sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==", "license": "MIT", - "peer": true, "dependencies": { "@next/env": "16.1.1", "@swc/helpers": "0.5.15", @@ -10971,17 +10995,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/npm-install-checks": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", @@ -11591,7 +11604,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -11601,7 +11613,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -11825,34 +11836,6 @@ "node": ">= 6" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/recma-build-jsx": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", @@ -12934,8 +12917,7 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", "devOptional": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/tapable": { "version": "2.3.0", @@ -13021,20 +13003,6 @@ "to-vfile": "^6.1.0" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/to-vfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-6.1.0.tgz", @@ -13207,7 +13175,6 @@ "integrity": "sha512-psrg8Rtnv4HPWCsoxId+MzEN8TVK5jeKCnTbnGAbTBqcDapR9hM41bJT/9eAyKn9C2MDG9Qjh3MkltAYuLDoXg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 18" }, @@ -13215,6 +13182,16 @@ "typedoc": "0.28.x" } }, + "node_modules/typedoc-plugin-zod": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/typedoc-plugin-zod/-/typedoc-plugin-zod-1.4.3.tgz", + "integrity": "sha512-j3kb4dGGK5OegtiIOH4F4etYdqq2lh+sTx6sABTmptPJJm8qx9XHyNlzfLYqW86ZVfL0hFR3+B/Ij9YXQw9TsA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typedoc": "0.23.x || 0.24.x || 0.25.x || 0.26.x || 0.27.x || 0.28.x" + } + }, "node_modules/typedoc/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -13237,7 +13214,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -13827,7 +13803,6 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -14221,7 +14196,7 @@ "version": "2.8.3", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", - "dev": true, + "devOptional": true, "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -14238,7 +14213,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.2.1.tgz", "integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/docs/website/src/lib/versions.ts b/docs/website/src/lib/versions.ts index 744c0a87ae..f2673d0c72 100644 --- a/docs/website/src/lib/versions.ts +++ b/docs/website/src/lib/versions.ts @@ -27,9 +27,10 @@ export interface VersionedSection { export const API_SECTION: VersionedSection = { basePath: '/sdk/api', - latest: 'v0.9.1', + latest: 'v0.10.0', versions: [ - { label: 'v0.9.1 (latest)', value: 'v0.9.1', isLatest: true }, + { label: 'v0.10.0 (latest)', value: 'v0.10.0', isLatest: true }, + { label: 'v0.9.1', value: 'v0.9.1' }, { label: 'v0.8.0', value: 'v0.8.0' }, { label: 'v0.7.0', value: 'v0.7.0' }, ], @@ -37,10 +38,10 @@ export const API_SECTION: VersionedSection = { export const RELEASE_NOTES_SECTION: VersionedSection = { basePath: '/sdk/release-notes', - latest: 'v0.9.1', + latest: 'v0.10.0', versions: [ - { label: 'v0.9.1 (latest)', value: 'v0.9.1', isLatest: true }, - { label: 'v0.9.0', value: 'v0.9.0' }, + { label: 'v0.10.0 (latest)', value: 'v0.10.0', isLatest: true }, + { label: 'v0.9.1', value: 'v0.9.1' }, { label: 'v0.8.0', value: 'v0.8.0' }, { label: 'v0.7.0', value: 'v0.7.0' }, ],