Skip to content

API Specification

The extension injects navigator.llm into web pages.

Low-level API for making requests.

navigator.llm.request(config: RequestConfig): Promise<Response>
interface RequestConfig {
action: string; // Action type
[key: string]: any; // Action-specific parameters
}
interface Response {
content?: string; // Generated content
data?: any; // Structured data
usage?: Usage; // Token usage
metadata?: Metadata; // Response metadata
}
interface Usage {
inputTokens: number;
outputTokens: number;
cost?: number;
}
interface Metadata {
provider: string;
model: string;
latency: number;
}
{
action: 'summarize',
input: string,
maxLength?: number,
style?: 'paragraph' | 'bullet-points' | 'tldr'
}

Response:

{
content: string,
usage: Usage,
metadata: Metadata
}
{
action: 'translate',
input: string,
targetLanguage: string,
formal?: boolean,
context?: string
}

Response:

{
content: string,
usage: Usage,
metadata: Metadata
}
{
action: 'extract',
input: string,
schema: Schema
}

Schema format:

type Schema = {
[key: string]: 'string' | 'number' | 'boolean' |
'string[]' | 'number[]' | Schema
}

Response:

{
data: any, // Matches schema structure
usage: Usage,
metadata: Metadata
}
{
action: 'classify',
input: string,
categories: string[]
}

Response:

{
data: {
category: string,
confidence: number
},
usage: Usage,
metadata: Metadata
}
{
action: 'answer',
question: string,
context: string,
concise?: boolean
}

Response:

{
content: string,
usage: Usage,
metadata: Metadata
}
{
action: 'generate',
prompt: string | Message[],
systemPrompt?: string,
maxTokens?: number,
temperature?: number,
stopSequences?: string[]
}

Message format:

interface Message {
role: 'system' | 'user' | 'assistant';
content: string;
}

Response:

{
content: string,
usage: Usage,
metadata: Metadata
}

For streaming responses, use the stream flag:

{
action: 'generate',
prompt: string,
stream: true
}

Returns a ReadableStream:

interface StreamChunk {
type: 'content' | 'done' | 'error';
content?: string;
error?: Error;
usage?: Usage;
metadata?: Metadata;
}

Example:

const response = await navigator.llm.request({
action: 'generate',
prompt: 'Write a story',
stream: true
});
const reader = response.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = JSON.parse(new TextDecoder().decode(value));
if (chunk.type === 'content') {
console.log(chunk.content);
}
}

Once standardized, the API will be:

interface NavigatorLLM {
getProvider(name: string): Promise<LLMProvider>;
listProviders(): Promise<ProviderInfo[]>;
}
interface LLMProvider {
readonly name: string;
readonly version: string;
readonly capabilities: ModelCapabilities;
createSession(config: SessionConfig): Promise<LLMSession>;
listModels(): Promise<ModelInfo[]>;
}
interface LLMSession {
generate(request: GenerateRequest): Promise<GenerateResponse>;
stream(request: GenerateRequest): Promise<ReadableStream<StreamChunk>>;
abort(): void;
close(): void;
}
interface ModelCapabilities {
maxTokens: number;
supportedModalities: ('text' | 'image' | 'audio')[];
supportsStreaming: boolean;
supportsTools: boolean;
contextWindow: number;
pricing?: ModelPricing;
}
interface ModelInfo {
id: string;
provider: string;
name: string;
description?: string;
capabilities: ModelCapabilities;
location: 'cloud' | 'local' | 'hybrid';
}

All errors include a code property:

  • EXTENSION_NOT_INSTALLED - Extension not detected
  • EXTENSION_DISABLED - Extension installed but disabled
  • PERMISSION_DENIED - User denied permission
  • PERMISSION_REQUIRED - Permission needs to be requested
  • ORIGIN_BLOCKED - Origin is blocked in settings
  • NO_PROVIDERS - No providers configured
  • ALL_PROVIDERS_FAILED - All providers failed
  • PROVIDER_ERROR - Specific provider error
  • INVALID_REQUEST - Malformed request
  • INVALID_SCHEMA - Invalid extraction schema
  • INVALID_ACTION - Unknown action type
  • RATE_LIMITED - Too many requests
  • QUOTA_EXCEEDED - Usage quota exceeded
  • TIMEOUT - Request timeout exceeded
  • ABORTED - Request aborted by user
interface WebLLMError extends Error {
name: 'WebLLMError';
code: string;
message: string;
details?: any;
provider?: string;
}

Example:

try {
await navigator.llm.request({ action: 'summarize', input: text });
} catch (error) {
console.error('Error code:', error.code);
console.error('Message:', error.message);
console.error('Details:', error.details);
}
const hasPermission = await navigator.llm.checkPermission();
// Returns: boolean

Automatically requested on first use, or manually:

const granted = await navigator.llm.requestPermission({
reason: 'To summarize articles for you'
});
// Returns: boolean

Check what’s available:

const capabilities = await navigator.llm.getCapabilities();
// {
// actions: ['summarize', 'translate', 'extract', 'classify', 'answer', 'generate'],
// streaming: true,
// providers: ['local', 'anthropic', 'openai'],
// version: '1.0.0'
// }

Get usage statistics:

const stats = await navigator.llm.getUsageStats();
// {
// today: {
// requests: 42,
// inputTokens: 15000,
// outputTokens: 3000,
// cost: 0.05
// },
// thisWeek: { ... },
// thisMonth: { ... }
// }

Future standard interface definition:

[Exposed=Window]
interface NavigatorLLM {
Promise<LLMProvider> getProvider(DOMString name);
Promise<sequence<ProviderInfo>> listProviders();
};
[Exposed=Window]
interface LLMProvider {
readonly attribute DOMString name;
readonly attribute DOMString version;
readonly attribute ModelCapabilities capabilities;
Promise<LLMSession> createSession(SessionConfig config);
Promise<sequence<ModelInfo>> listModels();
};
[Exposed=Window]
interface LLMSession {
Promise<GenerateResponse> generate(GenerateRequest request);
Promise<ReadableStream> stream(GenerateRequest request);
undefined abort();
undefined close();
};
dictionary GenerateRequest {
DOMString prompt;
DOMString? systemPrompt;
unsigned long? maxTokens;
double? temperature;
sequence<DOMString>? stopSequences;
};
dictionary GenerateResponse {
DOMString content;
Usage usage;
Metadata metadata;
};

API follows semantic versioning:

  • Major version - Breaking changes
  • Minor version - New features (backward compatible)
  • Patch version - Bug fixes

Current version: 1.0.0 (WIP)

Check version:

const version = await navigator.llm.getVersion();
// Returns: "1.0.0"