Skip to content

Commit 62604e8

Browse files
authored
QVAC-20837 fix: register built-in plugins for Bare examples; clarify Bare docs and error (#2640)
* QVAC-20837 fix: register built-in plugins for Bare examples; clarify Bare docs and error - bare-bootstrap.js: use bare-process/bare-path; load the default worker entry (dist/server/worker.js) to register the built-in plugin set before the example runs (initializeWorkerCore is idempotent). Warn if not built. - Rewrite WORKER_PLUGINS_NOT_REGISTERED message: register via plugins([...]) / registerPlugin(...) on Bare, import each plugin from its subpath, and recommend @qvac/bare-sdk for direct Bare usage. - Docs: @qvac/sdk README clarifies Bare needs explicit registration; @qvac/bare-sdk README adds a Connection lifecycle section (close(), unloadModel({ autoClose })). * QVAC-20837 doc: link WORKER_PLUGINS_NOT_REGISTERED to Bare runtime-registration docs - Add "Runtime registration on Bare" section to the Plugin system page, distinguishing bundle-time plugin selection from runtime registration. - Link the WORKER_PLUGINS_NOT_REGISTERED message to the new doc anchor. * QVAC-20837 doc: clarify bare-bootstrap default-worker scope in comment Explain that the harness loads the default worker only to run the registration-free bundled examples (the @qvac/sdk "full defaults" path), and that explicit/selective assembly is @qvac/bare-sdk's model.
1 parent 4b3ac99 commit 62604e8

5 files changed

Lines changed: 61 additions & 4 deletions

File tree

docs/website/content/docs/configuration/plugins/index.mdx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,25 @@ for await (const char of echoStream({ modelId, message: "Streaming test!" })) {
158158
await unloadModel({ modelId });
159159
```
160160

161+
## Runtime registration on Bare
162+
163+
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.
164+
165+
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:
166+
167+
```js
168+
import { plugins } from "@qvac/bare-sdk";
169+
import { llmPlugin } from "@qvac/bare-sdk/llamacpp-completion/plugin";
170+
171+
const sdk = plugins([llmPlugin]); // or registerPlugin(llmPlugin) from "@qvac/bare-sdk/plugins"
172+
```
173+
174+
Calls made before any plugin is registered raise `WorkerPluginsNotRegisteredError`.
175+
176+
<Callout type="info">
177+
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.
178+
</Callout>
179+
161180
## Notes
162181

163182
* 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.

packages/bare-sdk/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,23 @@ const result = await sdk.translate({
5353
| `@qvac/bare-sdk/ggml-vla/plugin` | `@qvac/vla-ggml` |
5454

5555

56+
## Connection lifecycle
57+
58+
`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:
59+
60+
```js
61+
import { close } from "@qvac/bare-sdk";
62+
63+
await unloadModel({ modelId });
64+
await close(); // tear down swarm + registry client so the process can exit
65+
```
66+
67+
Or opt into auto-close on the final unload:
68+
69+
```js
70+
await unloadModel({ modelId, autoClose: true });
71+
```
72+
5673
## Relationship to `@qvac/sdk`
5774

5875
`@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).

packages/sdk/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ See [https://docs.qvac.tether.io/sdk/getting-started](https://docs.qvac.tether.i
1616

1717
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.
1818

19-
> **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).
19+
> **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).
2020
2121
## Supported environments and installation
2222

packages/sdk/schemas/sdk-errors-client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ const clientErrorDefinitions: ErrorCodesMap = {
201201
[SDK_CLIENT_ERROR_CODES.WORKER_PLUGINS_NOT_REGISTERED]: {
202202
name: "WORKER_PLUGINS_NOT_REGISTERED",
203203
message: () =>
204-
"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.",
204+
"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",
205205
},
206206
[SDK_CLIENT_ERROR_CODES.BUNDLE_VERIFICATION_FAILED]: {
207207
name: "BUNDLE_VERIFICATION_FAILED",

packages/sdk/scripts/bare-bootstrap.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
*/
99

1010
import Module from "bare-module";
11-
import process from "process";
12-
import path from "path";
11+
import process from "bare-process";
12+
import path from "bare-path";
1313
import fs from "bare-fs";
1414
import { pathToFileURL } from "bare-url";
1515

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

49+
// This harness only runs the bundled examples, which stay registration-free
50+
// so one file works on Node, Expo, and Bare. Bare runs in-process with no
51+
// spawned worker, so nothing auto-registers — load the default worker to
52+
// register the full built-in set. This is deliberately the @qvac/sdk "full
53+
// defaults" path, not a usage reference; explicit/selective assembly is
54+
// @qvac/bare-sdk's model. initializeWorkerCore is idempotent, so the example's
55+
// getRPC() is fine.
56+
const workerEntry = path.resolve(process.cwd(), "dist/server/worker.js");
57+
if (fs.existsSync(workerEntry)) {
58+
Module.load(pathToFileURL(workerEntry), null, {
59+
imports: bareImports,
60+
conditions: ["bare", "import"],
61+
});
62+
} else {
63+
console.warn(
64+
`[bare-bootstrap] default worker entry not found at ${workerEntry}; ` +
65+
"examples that make SDK calls will fail to register plugins. " +
66+
"Run `bun run build` first.",
67+
);
68+
}
69+
4970
const absolutePath = path.resolve(process.cwd(), targetScript);
5071
const scriptUrl = pathToFileURL(absolutePath);
5172

0 commit comments

Comments
 (0)