|
| 1 | +# ClientAgentJS |
| 2 | + |
| 3 | +ClientAgentJS is a plain JavaScript browser library for adding AI agent capabilities to web applications without building your own backend. |
| 4 | + |
| 5 | +ClientAgentJS uses a **Zero-Backend Architecture**. Unlike traditional AI applications that proxy requests through a server, this library runs entirely in the browser. It follows a **Direct Client-to-Provider** model where the user's credentials never leave their device and requests go directly from the browser to the AI provider. |
| 6 | + |
| 7 | +## Use Cases |
| 8 | + |
| 9 | +- **User Form Assistance**: Enhance public-facing web forms with AI capabilities for text generation, translation, or content improvement—helping end users fill out profiles, reviews, or applications without changing your backend. |
| 10 | +- **Admin & Editor Form Assistance**: Restrict AI-powered form assistance to internal users, administrators, or content editors. Streamline product descriptions, service listings, CRM entries, and internal tool workflows while maintaining control over who accesses the AI features. |
| 11 | +- **Internal & Productivity Tools**: Build tools for teams that already have their own AI keys, avoiding infrastructure costs and privacy concerns. |
| 12 | +- **Contextual Web Assistants**: Create agents that read the current page content or user selection to provide summaries or answer questions. |
| 13 | +- **Creative Editors**: Integrate AI help directly into writing tools, CMS editors, or image generators where the user controls their own consumption. |
| 14 | +- **Rapid Prototyping**: Validate AI-powered ideas in minutes without setting up any server-side environment. |
| 15 | +- **Multi-Provider Apps**: Allow users to choose between OpenAI, Anthropic, or local models (via Ollama) within the same interface. |
| 16 | + |
| 17 | +## Key Features |
| 18 | + |
| 19 | +- **Zero-Backend**: No proxy servers, no hidden costs. Your browser talks directly to the AI provider. |
| 20 | +- **Multi-Provider**: Native support for OpenAI, Anthropic (Claude), and Google (Gemini). |
| 21 | +- **Automatic Retries**: Built-in resilience against transient network errors and rate limiting (429) with exponential backoff. |
| 22 | +- **Detailed Error Reporting**: Captures and displays descriptive error messages directly from the AI providers to simplify debugging. |
| 23 | +- **Global Distribution**: Available as both ESM modules and a global `ClientAgent` object for classic web environments. |
| 24 | +- **MCP Compatible**: Connect your agent to the vast ecosystem of Model Context Protocol tools and servers. |
| 25 | +- **Privacy First**: API keys and conversation history stay in your browser's local/session storage. |
| 26 | + |
| 27 | +## Model Context Protocol (MCP) |
| 28 | + |
| 29 | +ClientAgentJS supports the **Model Context Protocol**, allowing agents to use external tools and data sources. |
| 30 | + |
| 31 | +- **External Tools**: Connect to any MCP server that supports the `streamable-http` transport (or compatible SSE/JSON-RPC over HTTP). |
| 32 | +- **The CORS Challenge**: Since the library runs entirely in the browser, external MCP servers must support **CORS** (Cross-Origin Resource Sharing). |
| 33 | +- **Hosting Options**: |
| 34 | + - **Local Servers**: Users can run MCP servers on their own machines (localhost) to interact with local files or databases. |
| 35 | + - **Provider Servers**: Application developers can host and provide their own MCP servers pre-configured for their users. |
| 36 | + - **Shared Servers**: Reuse the same MCP configuration across different profiles and sessions. |
| 37 | + |
| 38 | +For more details on implementing or connecting to MCP servers, see the [MCP Tools example](examples/mcp-tools/). |
| 39 | + |
| 40 | +## What it does not require |
| 41 | + |
| 42 | +- no backend owned by the application developer |
| 43 | +- no framework |
| 44 | +- no Node.js at runtime |
| 45 | +- no bundler to consume the distributed library |
| 46 | + |
| 47 | +## What it provides |
| 48 | + |
| 49 | +- `createAgent()` with no required arguments |
| 50 | +- profile storage in `sessionStorage` or `localStorage` |
| 51 | +- `ask()` for one-shot requests |
| 52 | +- `stream()` for streaming responses |
| 53 | +- `createSession()` for multi-turn conversations |
| 54 | +- provider adapters for OpenAI-compatible, Anthropic-native and Google-native profiles |
| 55 | +- optional MCP server configuration per profile |
| 56 | +- optional local tool registration |
| 57 | +- a browser configuration panel for profiles and MCP servers |
| 58 | + |
| 59 | +## Development |
| 60 | + |
| 61 | +Build the distributable files: |
| 62 | + |
| 63 | +```bash |
| 64 | +npm run build |
| 65 | +``` |
| 66 | + |
| 67 | +Run tests: |
| 68 | + |
| 69 | +```bash |
| 70 | +npm test |
| 71 | +``` |
| 72 | + |
| 73 | +## Getting Started |
| 74 | + |
| 75 | +### Installation |
| 76 | + |
| 77 | +```bash |
| 78 | +npm install clientagentjs |
| 79 | +``` |
| 80 | + |
| 81 | +Or use it directly in the browser via a `<script>` tag: |
| 82 | + |
| 83 | +```html |
| 84 | +<script src="dist/clientagentjs.global.js"></script> |
| 85 | +<script> |
| 86 | + // Access via the global variable ClientAgent |
| 87 | + const agent = ClientAgent.createAgent({ |
| 88 | + storageKey: "my-app-unique-key" |
| 89 | + }); |
| 90 | +</script> |
| 91 | +``` |
| 92 | + |
| 93 | +### Basic Usage |
| 94 | + |
| 95 | +```javascript |
| 96 | +import { createAgent } from 'clientagentjs'; |
| 97 | + |
| 98 | +const agent = createAgent(); |
| 99 | + |
| 100 | +// Check if a profile is configured |
| 101 | +if (!agent.isReady()) { |
| 102 | + agent.openConfigPanel(); |
| 103 | +} |
| 104 | + |
| 105 | +// Simple request |
| 106 | +const response = await agent.ask("Hello, who are you?"); |
| 107 | +console.log(response.text); |
| 108 | + |
| 109 | +// Streaming request |
| 110 | +for await (const chunk of agent.stream("Tell me a story")) { |
| 111 | + process.stdout.write(chunk.delta); |
| 112 | +} |
| 113 | +``` |
| 114 | + |
| 115 | +## Streaming |
| 116 | + |
| 117 | +```js |
| 118 | +const controller = new AbortController() |
| 119 | + |
| 120 | +for await (const chunk of agent.stream("Write a headline", { |
| 121 | + signal: controller.signal |
| 122 | +})) { |
| 123 | + console.log(chunk.text) |
| 124 | +} |
| 125 | +``` |
| 126 | + |
| 127 | +## Sessions |
| 128 | + |
| 129 | +```js |
| 130 | +const session = agent.createSession() |
| 131 | + |
| 132 | +await session.ask("Who won the previous round?") |
| 133 | +await session.ask("Now summarize it in one sentence.") |
| 134 | +``` |
| 135 | + |
| 136 | +## Profiles and import/export |
| 137 | + |
| 138 | +Profiles store provider, model, credentials, prompt defaults and related options. MCP server configuration is stored separately and referenced from profiles. |
| 139 | + |
| 140 | +```js |
| 141 | +const backup = agent.exportProfiles() |
| 142 | +agent.importProfiles(backup) |
| 143 | +``` |
| 144 | + |
| 145 | +Calling `importProfiles()` always shows a confirmation warning before replacing the current profiles and MCP configuration. |
| 146 | + |
| 147 | +## Local tools |
| 148 | + |
| 149 | +The agent can register developer-defined tools that run in the browser and can be used automatically by compatible providers. |
| 150 | + |
| 151 | +```js |
| 152 | +agent.registerTool("calculate_sum", ({ numbers }) => { |
| 153 | + return { |
| 154 | + total: numbers.reduce((acc, value) => acc + Number(value || 0), 0) |
| 155 | + } |
| 156 | +}) |
| 157 | +``` |
| 158 | + |
| 159 | +Public methods: |
| 160 | + |
| 161 | +- `registerTool(name, handler)` |
| 162 | +- `unregisterTool(name)` |
| 163 | +- `listTools()` |
| 164 | +- `runTool(name, input)` |
| 165 | + |
| 166 | +Tool handlers receive one input object and can return plain JSON-compatible data or a string. If the tool is used through model tool-calling, the result is serialized and injected back into the model flow. |
| 167 | + |
| 168 | +Use local tools for lightweight client-side actions. For advanced or external integrations, prefer MCP servers. |
| 169 | + |
| 170 | +## Configuration panel |
| 171 | + |
| 172 | +The built-in UI opens from the public API: |
| 173 | + |
| 174 | +```js |
| 175 | +agent.openConfigPanel() |
| 176 | +agent.openMcpPanel() |
| 177 | +``` |
| 178 | + |
| 179 | +The built-in panels use English translations. |
| 180 | + |
| 181 | +## Provider types |
| 182 | + |
| 183 | +The profile field `providerType` selects the adapter implementation: |
| 184 | + |
| 185 | +- `openai-compatible` |
| 186 | +- `anthropic-native` |
| 187 | +- `google-native` |
| 188 | + |
| 189 | +## CORS |
| 190 | + |
| 191 | +Since ClientAgentJS runs entirely in the browser, it requires AI providers to support **CORS** (Cross-Origin Resource Sharing). Not all providers enable CORS by default, and some require special configuration. |
| 192 | + |
| 193 | +### Provider CORS Support |
| 194 | + |
| 195 | +- **Anthropic**: Supports browser access when the `anthropic-dangerous-direct-browser-access` header is included. Handled automatically by the library. |
| 196 | +- **Google (Gemini)**: Supports CORS on the generative language API. No additional configuration needed. |
| 197 | +- **OpenAI**: Does **not** support direct browser access. Use a backend proxy or [OpenRouter](#openrouter) instead. |
| 198 | +- **Ollama**: Requires manual CORS configuration (see below). |
| 199 | +- **Other OpenAI-compatible providers**: CORS support varies. Check their documentation, or use OpenRouter as a unified alternative. |
| 200 | + |
| 201 | +### When a Provider Does Not Support CORS |
| 202 | + |
| 203 | +1. **Use your own backend proxy**: Route API requests through a server you control, then point ClientAgentJS at your proxy endpoint using an OpenAI-compatible configuration. |
| 204 | +2. **Use OpenRouter**: [OpenRouter](https://openrouter.ai) supports CORS and provides access to models from OpenAI, Anthropic, Mistral, Meta, and many others through a single endpoint — useful when you need browser-compatible access to models whose native APIs do not support it. |
| 205 | +3. **Use a public CORS proxy** *(development only)*: Services like `cors-anywhere` can add CORS headers to proxied requests, but are unreliable and should not be used in production. |
| 206 | + |
| 207 | +### Ollama CORS Configuration |
| 208 | + |
| 209 | +Ollama does not enable CORS by default. To use it with ClientAgentJS, start Ollama with the appropriate CORS headers: |
| 210 | + |
| 211 | +```bash |
| 212 | +OLLAMA_ORIGINS="*" ollama serve |
| 213 | +``` |
| 214 | + |
| 215 | +Or set the environment variable permanently: |
| 216 | + |
| 217 | +```bash |
| 218 | +# Linux/macOS |
| 219 | +export OLLAMA_ORIGINS="*" |
| 220 | +ollama serve |
| 221 | + |
| 222 | +# Windows |
| 223 | +set OLLAMA_ORIGINS=* |
| 224 | +ollama serve |
| 225 | +``` |
| 226 | + |
| 227 | +For production environments, restrict origins to your specific domain instead of `*`: |
| 228 | + |
| 229 | +```bash |
| 230 | +OLLAMA_ORIGINS="http://localhost:*" ollama serve |
| 231 | +``` |
| 232 | + |
| 233 | +### MCP and CORS |
| 234 | + |
| 235 | +MCP servers also need to support CORS when accessed from the browser. Many MCP servers are designed to run as local processes and are not built for direct browser access. |
| 236 | + |
| 237 | +**Options:** |
| 238 | + |
| 239 | +1. **Run MCP servers locally**: A server on `localhost` accessed from a page also on `localhost` is same-origin and avoids cross-origin restrictions entirely. |
| 240 | +2. **Host your own MCP servers**: Configure them to include the appropriate `Access-Control-Allow-Origin` response headers. |
| 241 | +3. **Route through a backend proxy**: Forward browser requests to MCP servers through your own proxy, keeping the MCP servers unexposed. |
| 242 | + |
| 243 | +When adding an MCP server in the configuration panel, verify that the endpoint either supports CORS or is running on localhost. |
| 244 | + |
| 245 | +## Examples |
| 246 | + |
| 247 | +- [**Chat Explorer**](examples/browser-basic/): A full-featured chat interface demonstrating sessions, streaming, event logs, and configuration portability. |
| 248 | +- [**Form Assistance**](examples/form-assistance/): Using the agent to help users fill out and improve content in standard web forms. |
| 249 | +- [**MCP Tools**](examples/mcp-tools/): Connecting the agent to external services via the Model Context Protocol. |
| 250 | + |
| 251 | +## API and Documentation |
| 252 | + |
| 253 | +- [**Documentation Index**](docs/README.md) |
| 254 | +- [**API Contract**](docs/api.md) |
| 255 | +- [**Architecture Overview**](docs/architecture.md) |
| 256 | + |
| 257 | +### Deployment Models |
| 258 | + |
| 259 | +- **Direct Client-to-Provider**: The browser connects directly to OpenAI, Anthropic, or Ollama using credentials stored locally. This ensures maximum privacy and zero infrastructure costs for the developer. |
| 260 | +- **Managed Proxy**: The developer provides an endpoint that acts as a thin proxy to inject keys or manage quotas. The library still manages the agent logic, history, and tools in the browser. |
| 261 | +- **Local-Only**: The agent communicates with a local model (like Ollama or LM Studio) for a 100% private, offline-capable experience. |
| 262 | + |
| 263 | +This architecture makes the project ideal for internal tools, developer-focused products, and any application where data privacy and user control are priorities. |
0 commit comments