Extension Bridge
@divinci-ai/extension-bridge lets any website talk to the Divinci Local
Inference browser extension, so chat runs on the user’s device — private,
free, and with no server round-trip — and falls back to the Divinci cloud API
when the extension isn’t installed.
It has zero Divinci-internal dependencies and works in any browser. Unlike the other packages here, it is designed to be dropped into a site that has nothing else of ours in it.
npm install @divinci-ai/extension-bridgeQuick start
Section titled “Quick start”import { createDivinciBridge } from "@divinci-ai/extension-bridge";
// cloudChat is your existing cloud path — wire it to @divinci-ai/client.// Omit it to require the extension.const divinci = createDivinciBridge({ cloudChat });
const { fullText, source } = await divinci.chat( { messages: [{ role: "user", content: "Summarize this page." }] }, { onToken: (delta) => append(delta) },);
console.log(source); // "extension" (on-device) or "cloud"source tells you which path served the turn, so you can badge on-device
responses differently, or track how often the extension is doing the work.
Consent
Section titled “Consent”The first time a site calls chat() through the extension, the user sees a
one-time in-page prompt — “Allow example.com to run AI chat on your device?”.
Detecting the extension
Section titled “Detecting the extension”const { present, extensionVersion, supportedModels } = await divinci.detect();if (present) showOnDeviceBadge();hasExtension() is a synchronous presence check when you only need a boolean
and can’t await.
Advanced surfaces
Section titled “Advanced surfaces”These reach the extension directly and have no cloud equivalent:
await divinci.requestAccess(["chat"]); // pre-warm the consent promptconst card = await divinci.agentCard(); // the local agent's A2A Agent Cardconst task = await divinci.task("..."); // submit an A2A task to the local agentBehaviour without an extension is deliberately asymmetric, so a missing extension never looks like a silent success:
| Call | No extension present |
|---|---|
chat() | falls back to cloudChat, or rejects if you didn’t supply one |
detect() | resolves with present: false |
hasExtension() | returns false |
requestAccess() | returns [] |
agentCard() / task() | reject |
Consent scopes
Section titled “Consent scopes”ConsentScope is "chat" | "webmcp" | "a2a". Request only what you use —
a site asking for all three gets a broader prompt and is likelier to be denied.
How it works
Section titled “How it works”The extension injects window.divinci from a MAIN-world content script. This
package is a thin, dependency-injected dispatcher over it: extension-first,
cloud-fallback.
All dispatch logic is pure — both window and cloudChat are options — so
it is fully testable without a browser, and you can unit-test your integration
by passing a fake.
const divinci = createDivinciBridge({ win: fakeWindow, // inject a stub instead of the real window cloudChat: fakeCloudChat,});