> aimask --info
● window.aimask · MV3 · v0.1
Your code, the tokens of whoever uses it
Make what you want.
[ no keys ]
You never touch an API key. Theirs stays in their browser.
[ no bill ]
They pay for what they use. You get no bill.
[ no backend ]
No server. One window.aimask call on the page.
> aimask --quickstart
Quickstart
$ aimask install# add the sdk
Types, a detector, named errors. Zero deps.
> shellbash
npm install @aimask/sdk$ aimask detect# find the provider
Injected at document_start. null means not installed.
> detect.tstypescript
import { getAimask } from "@aimask/sdk";
const aimask = getAimask(); // Aimask | null
if (aimask === null) {
// extension not installed, link the user to install it
}$ aimask session# request a budget
First call opens consent and a budget. Silent after that, until spent or revoked.
> session.tstypescript
const status = await aimask.availability();
// "available" | "requires-consent" | "unavailable"
const opened = await aimask.requestSession({
needs: { context: null, vision: null, tools: null, json: null },
prefer: { tier: "fast", models: null },
intent: "Summarize the current article",
});
if (!opened.ok) return; // opened.error.code explains why
const session = opened.data;$ aimask chat# run a completion
Every field is explicit. What you send is what runs.
> chat.tstypescript
const result = await session.chat({
messages: [
{
role: "user",
content: "Hello",
name: null,
tool_call_id: null,
tool_calls: null,
},
],
tools: null,
tool_choice: null,
response_format: null,
temperature: null,
max_tokens: 300,
stop: null,
signal: null,
});
if (!result.ok) return; // result.error.code
console.log(result.data.message.content);! NOTE No default spends their money. If it isn't in the call, it doesn't happen.
$ aimask stream# token by token
Same shape as chat. Pass an AbortSignal to stop.
> stream.tstypescript
const stream = session.chatStream({
/* same shape as chat */
});
for await (const delta of stream) {
if (!delta.ok) break; // delta.error.code
if (delta.data.content) {
process.stdout.write(delta.data.content);
}
}$ aimask errors# typed errors & events
Nothing throws. Errors come back with a named code. Subscribe to budget and connection changes.
> errors.tstypescript
import { ERROR_CODES } from "@aimask/sdk";
const result = await session.chat(/* ... */);
if (!result.ok && result.error.code === ERROR_CODES.BUDGET_EXCEEDED) {
// the per-origin allowance is exhausted
}
aimask.on("budgetlow", () => {}); // 80% of the origin budget reached
aimask.on("disconnect", () => {}); // session revoked or extension locked
aimask.on("modelchanged", (data) => {}); // resolved model changed> aimask --errors --list
Error codes
| Code | Name | Meaning |
|---|---|---|
| 4001 | USER_REJECTED | User said no. |
| 4100 | UNAUTHORIZED | No active session for this site. |
| 4200 | BUDGET_EXCEEDED | This site's allowance is used up. |
| 4290 | RATE_LIMITED | This site is asking too fast. |
| 4400 | CAPABILITY_UNAVAILABLE | No model can do what was asked. |
| 4900 | DISCONNECTED | Extension locked or model unreachable. |
| 5000 | PROVIDER_ERROR | The model's provider failed. |