Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/website/content/docs/configuration/plugins/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,25 @@ for await (const char of echoStream({ modelId, message: "Streaming test!" })) {
await unloadModel({ modelId });
```

## Runtime registration on Bare

The `plugins` array in `qvac.config.*` is **bundle-time** configuration — it controls which addons get packed into your worker. That is separate from **runtime registration**, which determines the plugins live in the worker process when an SDK call runs.

On Node.js and Expo the SDK spawns a worker that auto-registers the full built-in set, so you never register manually. **Bare runs in-process with no spawned worker**, so nothing auto-registers — register the plugins you use before the first SDK call:

```js
import { plugins } from "@qvac/bare-sdk";
import { llmPlugin } from "@qvac/bare-sdk/llamacpp-completion/plugin";

const sdk = plugins([llmPlugin]); // or registerPlugin(llmPlugin) from "@qvac/bare-sdk/plugins"
```

Calls made before any plugin is registered raise `WorkerPluginsNotRegisteredError`.

<Callout type="info">
For direct Bare usage we recommend [`@qvac/bare-sdk`](https://github.com/tetherto/qvac/tree/main/packages/bare-sdk) — the slim distribution built for explicit assembly. `@qvac/sdk` also runs on Bare; import the same plugins from `@qvac/sdk/<capability>/plugin` instead.
</Callout>

## Notes

* In `qvac.config.*`, if `plugins` is omitted or set to an empty array, the SDK bundles all built-in plugins. If `plugins` is set, it bundles only the listed plugins.
Expand Down
17 changes: 17 additions & 0 deletions packages/bare-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,23 @@ const result = await sdk.translate({
| `@qvac/bare-sdk/ggml-vla/plugin` | `@qvac/vla-ggml` |


## Connection lifecycle

`unloadModel` does not close the SDK's connections. The swarm, registry client, and corestore stay up so long-lived workers survive a routine unload across load/unload cycles. Close explicitly when you're done:

```js
import { close } from "@qvac/bare-sdk";

await unloadModel({ modelId });
await close(); // tear down swarm + registry client so the process can exit
```

Or opt into auto-close on the final unload:

```js
await unloadModel({ modelId, autoClose: true });
```

## Relationship to `@qvac/sdk`

`@qvac/bare-sdk` is built by copying compiled output from `@qvac/sdk`. The two packages share the same source, version, and release branch; the only differences are package metadata (slim dependency profile, no default worker entry, explicit assembly API).
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ See [https://docs.qvac.tether.io/sdk/getting-started](https://docs.qvac.tether.i

For AI/LLM tools, use [https://docs.qvac.tether.io/llms-full.txt](https://docs.qvac.tether.io/llms-full.txt) as the consolidated plaintext documentation export.

> **Assembling a custom worker on Bare?** See [`@qvac/bare-sdk`](../bare-sdk/README.md) — the same SDK surface with no built-in plugin addons, designed for consumers wiring their own worker entry (Pear apps, bare-expo apps, direct Bare scripts).
> **Running on Bare directly?** `@qvac/sdk` runs on Bare, but you must register the plugins you use explicitly before the first SDK call (Node and Expo do this automatically). For direct Bare usage we recommend [`@qvac/bare-sdk`](../bare-sdk/README.md) — the same SDK surface with no built-in plugin addons, designed for consumers wiring their own worker entry (Pear apps, bare-expo apps, direct Bare scripts).

## Supported environments and installation

Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/schemas/sdk-errors-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ const clientErrorDefinitions: ErrorCodesMap = {
[SDK_CLIENT_ERROR_CODES.WORKER_PLUGINS_NOT_REGISTERED]: {
name: "WORKER_PLUGINS_NOT_REGISTERED",
message: () =>
"No plugins registered in the worker. Call `plugins([...])` (or `registerPlugin(...)`) before the first SDK call. Import default plugin manifests from `@qvac/sdk/server/bare/plugins` if you want the full built-in set.",
"No plugins registered in the worker. On Bare, register the plugins you need with `plugins([...])` (or `registerPlugin(...)`) before the first SDK call — import each from its subpath, e.g. `@qvac/sdk/llamacpp-completion/plugin`. For direct Bare usage we recommend the dedicated `@qvac/bare-sdk` package. See https://docs.qvac.tether.io/configuration/plugins#runtime-registration-on-bare",
},
[SDK_CLIENT_ERROR_CODES.BUNDLE_VERIFICATION_FAILED]: {
name: "BUNDLE_VERIFICATION_FAILED",
Expand Down
25 changes: 23 additions & 2 deletions packages/sdk/scripts/bare-bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
*/

import Module from "bare-module";
import process from "process";
import path from "path";
import process from "bare-process";
import path from "bare-path";
import fs from "bare-fs";
import { pathToFileURL } from "bare-url";

Expand Down Expand Up @@ -46,6 +46,27 @@ if (!process.stdout.write) {
const bareImportsPath = path.join(process.cwd(), "bare-imports.json");
const bareImports = JSON.parse(fs.readFileSync(bareImportsPath, "utf-8"));

// This harness only runs the bundled examples, which stay registration-free
// so one file works on Node, Expo, and Bare. Bare runs in-process with no
// spawned worker, so nothing auto-registers — load the default worker to
// register the full built-in set. This is deliberately the @qvac/sdk "full
// defaults" path, not a usage reference; explicit/selective assembly is
// @qvac/bare-sdk's model. initializeWorkerCore is idempotent, so the example's
// getRPC() is fine.
const workerEntry = path.resolve(process.cwd(), "dist/server/worker.js");
if (fs.existsSync(workerEntry)) {
Module.load(pathToFileURL(workerEntry), null, {
imports: bareImports,
conditions: ["bare", "import"],
});
} else {
console.warn(
`[bare-bootstrap] default worker entry not found at ${workerEntry}; ` +
"examples that make SDK calls will fail to register plugins. " +
"Run `bun run build` first.",
);
}
Comment thread
lauripiisang marked this conversation as resolved.

const absolutePath = path.resolve(process.cwd(), targetScript);
const scriptUrl = pathToFileURL(absolutePath);

Expand Down
Loading