Private chat · streaming · long context

Prompt API

Stream private chats, render Markdown, return schema-constrained JSON, and keep long sessions useful.
Documentation

Runs in this browser

Interactive playground

No hosted fallback

Use it in your product

Start complete. Customize when you need to.

Components provide the fastest production path. Composables expose the same lifecycle for a UI that is entirely yours.

Vue component

Ship the complete chat experience

Persistence, streaming, session restoration, Markdown and context compaction are already wired together.
Vue component
<script setup lang="ts">
import { ref } from "vue";
import { PromptApi } from "@desource/browser-ai-vue";
import "@desource/browser-ai-vue/assets/lib.css";

const starterMessages = [{
  id: "welcome",
  role: "assistant" as const,
  content: "## Ready\nAsk me anything about this page."
}];
</script>

<template>
  <PromptApi
    :initial-messages="starterMessages"
    system-prompt="Answer clearly and use Markdown."
    @prompt-complete="({ response }) => console.log(response)" />
</template>

Vue composable

Build a completely custom interface

Use the browser lifecycle directly while keeping availability, cancellation and session cleanup reactive.
Vue composable
<script setup lang="ts">
import { ref } from "vue";
import { usePromptApi } from "@desource/browser-ai-vue";

const input = ref("Explain local AI in one sentence.");
const output = ref("");
const error = ref("");
// Creating the composable in setup also registers session cleanup.
const ai = usePromptApi();
const { isProcessing, interrupt } = ai;

async function run() {
  if (isProcessing.value) return;
  output.value = "";
  error.value = "";
  try {
    if (!ai.isReady.value) await ai.create();
    const reader = ai.promptStreaming(input.value).getReader();
    try {
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        output.value += value;
      }
    } finally {
      await reader.cancel().catch(() => undefined);
      reader.releaseLock();
    }
    
  } catch (cause) {
    if (cause instanceof DOMException && cause.name === "AbortError") return;
    error.value = cause instanceof Error ? cause.message : String(cause);
  }
}
</script>

<template>
  <textarea v-model="input" aria-label="Source text" />
  <button :disabled="isProcessing || !input.trim()" @click="run">Send</button>
  <button :disabled="!isProcessing" @click="interrupt">Stop</button>
  <p v-if="error" role="alert">{{ error }}</p>
  <pre>{{ output }}</pre>
</template>

One contract, native ergonomics

Use the same capability in every supported stack.

Vue composables, React hooks, Svelte stores, Angular signals, Nuxt auto-imports, and the TypeScript core all delegate browser behavior to the same tested runtime.

Vue

Vue component

Use the ready-made component or the matching use* composable.
Vue
<script setup lang="ts">
import { PromptApi } from "@desource/browser-ai-vue";
import "@desource/browser-ai-vue/assets/lib.css";
</script>

<template><PromptApi /></template>

React

React component

The matching hook exposes the same core operations for a custom interface.
React
import { PromptApi } from "@desource/browser-ai-react";
import "@desource/browser-ai-react/assets/lib.css";

export function Feature() {
  return <PromptApi />;
}

Svelte

Svelte component

Use the component or its create* controller with a readable state store.
Svelte
<script lang="ts">
  import { PromptApi } from "@desource/browser-ai-svelte";
  import "@desource/browser-ai-svelte/assets/lib.css";
</script>

<PromptApi />

Angular

Angular standalone component

Standalone components pair with signal controllers and BrowserAiService.
Angular
import { Component } from "@angular/core";
import { BrowserAiPromptApiComponent } from "@desource/browser-ai-angular";
import "@desource/browser-ai-angular/assets/lib.css";

@Component({
  standalone: true,
  imports: [BrowserAiPromptApiComponent],
  template: `<browser-ai-prompt-api />`
})
export class FeatureComponent {}

Nuxt

Nuxt auto-import

The Nuxt module registers the Vue component on the client and protects SSR.
Nuxt
export default defineNuxtConfig({
  modules: ["@desource/browser-ai-nuxt"]
});

// app/pages/feature.vue
<template><PromptApi /></template>

TypeScript core

Framework-neutral controller

Start from a real click, handle browser errors, and release the native session after the result.
TypeScript core
import { createPromptApi } from "@desource/browser-ai";

const button = document.createElement("button");
const output = document.createElement("pre");
button.textContent = "Run PromptApi";
document.body.append(button, output);

button.addEventListener("click", async () => {
  button.disabled = true;
  const api = createPromptApi();
  try {
    const result = await api.prompt("Reply in one sentence.");
    output.textContent = typeof result === "string" ? result : JSON.stringify(result, null, 2);
  } catch (error) {
    output.textContent = error instanceof Error ? error.message : String(error);
  } finally {
    api.dispose();
    button.disabled = false;
  }
});