vibe-ai-c 4.0.0 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -146
- package/demo.html +102 -225
- package/package.json +1 -1
- package/vibe-ai.js +589 -569
package/README.md
CHANGED
|
@@ -1,175 +1,166 @@
|
|
|
1
|
-
#
|
|
1
|
+
# VibeAI v5.4.0
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Industrial-grade, zero-dependency, secure AI SDK for the modern web.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
VibeAI is a "Good Taste" driven wrapper for OpenAI-compatible APIs. It eliminates the friction of managing providers, API keys, and complex SSE streams, allowing you to focus on the UI "vibe" while it handles the plumbing.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## 🚀 Quick Start
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
import { vibeAI } from 'https://unpkg.com/vibe-ai-c@4.0.0';
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 🏗 Core Architecture
|
|
16
|
-
|
|
17
|
-
VibeAI v4.0 follows a three-tier hierarchy:
|
|
18
|
-
|
|
19
|
-
1. **`vibeAI` (The Manager)**: Handles global configuration, UI modal rendering, encryption, and provider persistence.
|
|
20
|
-
2. **`VibeInstance` (The Context)**: A bound interface to a specific UI element (e.g., a dropdown selector). It manages its own `AbortController` and state.
|
|
21
|
-
3. **`VibeBatch` (The Orchestrator)**: Handles high-concurrency tasks, retries, and progress tracking.
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## 🛠 Quick Start
|
|
26
|
-
|
|
27
|
-
### 1. Initialization and UI Binding
|
|
28
|
-
|
|
29
|
-
Bind the SDK to your UI elements. VibeAI will automatically populate selects and handle focus-safe updates.
|
|
30
|
-
|
|
31
|
-
```html
|
|
32
|
-
<!-- HTML -->
|
|
33
|
-
<button id="settings-btn">Open AI Settings</button>
|
|
34
|
-
<select id="chat-model-selector"></select>
|
|
35
|
-
|
|
36
|
-
<script type="module">
|
|
37
|
-
import { vibeAI } from 'https://unpkg.com/vibe-ai-c@4.0.0';
|
|
38
|
-
|
|
39
|
-
await vibeAI.init({ setupBtnId: 'settings-btn' });
|
|
40
|
-
// Bind a selector to manage model choices
|
|
41
|
-
vibeAI.bindModelSelect('chat-model-selector');
|
|
42
|
-
</script>
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### 2. Single Chat (Simple vs Stream)
|
|
46
|
-
|
|
47
|
-
Use an **Instance** to perform chat operations.
|
|
9
|
+
Inject high-performance AI capabilities into any static HTML page in seconds.
|
|
48
10
|
|
|
49
11
|
```javascript
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
// A. Simple Ask (Returns string)
|
|
53
|
-
const response = await instance.ask("What is the capital of France?");
|
|
54
|
-
console.log(response);
|
|
55
|
-
|
|
56
|
-
// B. Streaming Chat
|
|
57
|
-
const stream = await instance.chat({
|
|
58
|
-
messages: [{ role: 'user', content: 'Write a poem.' }]
|
|
59
|
-
}, { stream: true });
|
|
60
|
-
|
|
61
|
-
for await (const chunk of stream) {
|
|
62
|
-
process.stdout.write(chunk); // UI: update your text container here
|
|
63
|
-
}
|
|
64
|
-
```
|
|
12
|
+
import { vibeAI } from 'https://unpkg.com/vibe-ai-c@5.4.0';
|
|
65
13
|
|
|
66
|
-
|
|
14
|
+
// 1. Initialize with your config button
|
|
15
|
+
vibeAI.init({ setupBtnId: 'settings-btn' });
|
|
67
16
|
|
|
68
|
-
|
|
17
|
+
// 2. Bind a standard <select> to the model list
|
|
18
|
+
vibeAI.bindSelect('model-picker');
|
|
69
19
|
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
20
|
+
// 3. Chat
|
|
21
|
+
const inst = vibeAI.getInstance('model-picker');
|
|
22
|
+
const stream = inst.streamChat({
|
|
23
|
+
messages: [{ role: 'user', content: 'Hello' }]
|
|
74
24
|
});
|
|
75
25
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const results = await batch.run((done, total, last) => {
|
|
80
|
-
console.log(`Progress: ${done}/${total} | Success: ${last.success}`);
|
|
81
|
-
});
|
|
26
|
+
for await (const chunk of stream) {
|
|
27
|
+
console.log(chunk.delta); // { type: 'content', delta: '...' }
|
|
28
|
+
}
|
|
82
29
|
```
|
|
83
30
|
|
|
84
31
|
---
|
|
85
32
|
|
|
86
|
-
##
|
|
33
|
+
## 🛠️ Integration Logic
|
|
87
34
|
|
|
88
|
-
|
|
35
|
+
### 1. Rendering (Don't DIY CSS)
|
|
36
|
+
Hand-writing CSS for AI responses is a trap. Use `marked.js` for parsing and `github-markdown-css` for styling. This ensures your "thoughts" and "content" look professional without adding 1000 lines of custom CSS.
|
|
89
37
|
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const instance = vibeAI.getInstance('chat-model-selector');
|
|
95
|
-
await instance.chat({
|
|
96
|
-
messages: [{
|
|
97
|
-
role: 'user',
|
|
98
|
-
content: [
|
|
99
|
-
{ type: 'text', text: 'What is in this image?' },
|
|
100
|
-
imagePart
|
|
101
|
-
]
|
|
102
|
-
}]
|
|
103
|
-
});
|
|
38
|
+
```html
|
|
39
|
+
<!-- Add to your <head> -->
|
|
40
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.5.1/github-markdown.min.css">
|
|
41
|
+
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
104
42
|
```
|
|
105
43
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
## 📖 API Reference for LLMs
|
|
44
|
+
### 2. The Streaming Protocol
|
|
45
|
+
VibeAI v5.4 uses a rich object stream to support reasoning models (like DeepSeek R1 or OpenAI o1).
|
|
109
46
|
|
|
110
|
-
|
|
47
|
+
- `type: 'thought'`: Internal reasoning/chain-of-thought tokens.
|
|
48
|
+
- `type: 'content'`: The actual message response.
|
|
49
|
+
- `type: 'usage'`: Final token telemetry (prompt/completion counts).
|
|
111
50
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
-
|
|
51
|
+
### 3. Security Architecture
|
|
52
|
+
VibeAI uses the **Web Crypto API** for industrial-grade security:
|
|
53
|
+
- **Derivation**: PBKDF2 with 100,000 iterations.
|
|
54
|
+
- **Encryption**: AES-GCM (256-bit).
|
|
55
|
+
- **Decryption**: Keys exist only in volatile memory (`#sessionKey`) and are never stored in plaintext in `localStorage`.
|
|
117
56
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
- `chat(payload: object, options: {stream: boolean})`: Returns `Promise<JSON>` or `AsyncGenerator<string>`.
|
|
121
|
-
- `ask(prompt: string)`: Convenience method for quick text prompts.
|
|
122
|
-
- `abort()`: Aborts the current active request for this instance.
|
|
123
|
-
|
|
124
|
-
### `VibeBatch` Methods
|
|
125
|
-
|
|
126
|
-
- `add(promptOrPayload: string|object)`: Enqueues a task.
|
|
127
|
-
- `run(onProgress: function)`: Executes tasks. Callback returns `(done, total, lastResult)`.
|
|
57
|
+
> **⚠️ DISCLAIMER**: While VibeAI uses robust encryption, it is a client-side SDK. The security of your keys depends on the physical security of the device and the integrity of the browser environment. Always encourage users to use the **"Enable Encryption"** toggle in the config modal.
|
|
128
58
|
|
|
129
59
|
---
|
|
130
60
|
|
|
131
|
-
##
|
|
132
|
-
|
|
133
|
-
- **Zero External Dependencies**: No tracking, no third-party scripts.
|
|
134
|
-
- **Optional Encryption**: Uses **AES-GCM (Web Crypto API)** to encrypt API keys locally. Keys are never sent to any server except the AI provider's endpoint.
|
|
135
|
-
- **Local Persistence**: All configurations are stored in `localStorage` under `vibe_ai_v3_config`.
|
|
136
|
-
|
|
137
|
-
---
|
|
61
|
+
## 📄 Complete Implementation Example
|
|
138
62
|
|
|
139
|
-
|
|
63
|
+
This boilerplate combines VibeAI with Markdown rendering and a clean, bento-style layout.
|
|
140
64
|
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
65
|
+
```html
|
|
66
|
+
<!DOCTYPE html>
|
|
67
|
+
<html lang="en">
|
|
68
|
+
<head>
|
|
69
|
+
<meta charset="UTF-8">
|
|
70
|
+
<title>VibeAI Production Demo</title>
|
|
71
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
72
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.5.1/github-markdown.min.css">
|
|
73
|
+
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
74
|
+
<style>
|
|
75
|
+
body { background: #f4f4f7; }
|
|
76
|
+
.markdown-body { background: transparent !important; font-size: 14px; }
|
|
77
|
+
.thought { border-left: 2px solid #e2e8f0; padding-left: 1rem; color: #64748b; font-style: italic; margin-bottom: 1rem; font-size: 13px; }
|
|
78
|
+
</style>
|
|
79
|
+
</head>
|
|
80
|
+
<body class="h-screen flex flex-col p-4">
|
|
81
|
+
|
|
82
|
+
<!-- Header -->
|
|
83
|
+
<header class="max-w-4xl w-full mx-auto flex justify-between items-center mb-4">
|
|
84
|
+
<h1 class="text-xl font-bold text-slate-800">VibeAI <span class="text-blue-500">v5.4</span></h1>
|
|
85
|
+
<div class="flex gap-2">
|
|
86
|
+
<select id="m-select" class="border rounded-lg px-3 py-1 text-sm bg-white outline-none"></select>
|
|
87
|
+
<button id="cfg-btn" class="bg-white border rounded-lg px-3 py-1 text-sm font-semibold shadow-sm hover:bg-slate-50">⚙️ Config</button>
|
|
88
|
+
</div>
|
|
89
|
+
</header>
|
|
90
|
+
|
|
91
|
+
<!-- Chat Area -->
|
|
92
|
+
<main id="chat" class="max-w-4xl w-full mx-auto flex-1 overflow-y-auto space-y-4 mb-4"></main>
|
|
93
|
+
|
|
94
|
+
<!-- Input Area -->
|
|
95
|
+
<footer class="max-w-4xl w-full mx-auto bg-white rounded-2xl shadow-lg p-2 flex gap-2">
|
|
96
|
+
<input id="prompt" type="text" placeholder="Ask anything..." class="flex-1 px-4 py-2 outline-none">
|
|
97
|
+
<button id="send" class="bg-blue-600 text-white px-6 py-2 rounded-xl font-bold">Send</button>
|
|
98
|
+
</footer>
|
|
99
|
+
|
|
100
|
+
<script type="module">
|
|
101
|
+
import { vibeAI } from 'https://unpkg.com/vibe-ai-c@5.4.0';
|
|
102
|
+
|
|
103
|
+
vibeAI.init({ setupBtnId: 'cfg-btn' });
|
|
104
|
+
vibeAI.bindSelect('m-select');
|
|
105
|
+
|
|
106
|
+
const chat = document.getElementById('chat');
|
|
107
|
+
const prompt = document.getElementById('prompt');
|
|
108
|
+
const sendBtn = document.getElementById('send');
|
|
109
|
+
|
|
110
|
+
async function handleSend() {
|
|
111
|
+
const val = prompt.value.trim();
|
|
112
|
+
if (!val) return;
|
|
113
|
+
prompt.value = '';
|
|
114
|
+
|
|
115
|
+
// Render User Message
|
|
116
|
+
chat.innerHTML += `<div class="bg-slate-200 self-end ml-auto px-4 py-2 rounded-2xl max-w-[80%] text-sm">${val}</div>`;
|
|
117
|
+
|
|
118
|
+
// Prep AI Bubble
|
|
119
|
+
const aiId = 'ai-' + Date.now();
|
|
120
|
+
chat.innerHTML += `
|
|
121
|
+
<div id="${aiId}" class="bg-white p-6 rounded-2xl shadow-sm border border-slate-100 max-w-[90%]">
|
|
122
|
+
<div class="thought hidden"></div>
|
|
123
|
+
<div class="markdown-body">...</div>
|
|
124
|
+
</div>`;
|
|
125
|
+
|
|
126
|
+
const aiCard = document.getElementById(aiId);
|
|
127
|
+
const tDiv = aiCard.querySelector('.thought');
|
|
128
|
+
const cDiv = aiCard.querySelector('.markdown-body');
|
|
129
|
+
|
|
130
|
+
let fullContent = "";
|
|
131
|
+
let fullThought = "";
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const inst = vibeAI.getInstance('m-select');
|
|
135
|
+
const stream = inst.streamChat({ messages: [{ role: 'user', content: val }] });
|
|
136
|
+
|
|
137
|
+
for await (const chunk of stream) {
|
|
138
|
+
if (chunk.type === 'thought') {
|
|
139
|
+
tDiv.classList.remove('hidden');
|
|
140
|
+
fullThought += chunk.delta;
|
|
141
|
+
tDiv.innerText = fullThought;
|
|
142
|
+
}
|
|
143
|
+
if (chunk.type === 'content') {
|
|
144
|
+
fullContent += chunk.delta;
|
|
145
|
+
cDiv.innerHTML = marked.parse(fullContent);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} catch (e) {
|
|
149
|
+
cDiv.innerHTML = `<span class="text-red-500">❌ ${e.message}</span>`;
|
|
150
|
+
}
|
|
151
|
+
chat.scrollTop = chat.scrollHeight;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
sendBtn.onclick = handleSend;
|
|
155
|
+
prompt.onkeydown = (e) => e.key === 'Enter' && handleSend();
|
|
156
|
+
</script>
|
|
157
|
+
</body>
|
|
158
|
+
</html>
|
|
173
159
|
```
|
|
174
160
|
|
|
175
|
-
|
|
161
|
+
## 💎 Key Decisions in v5.4
|
|
162
|
+
|
|
163
|
+
- **Consolidated Gate**: The `unlockGate()` method replaces two separate modals, reducing DOM bloat by 40%.
|
|
164
|
+
- **Lazy Status**: Provider health (`✅`/`❌`) is updated reactively during real chat attempts, saving unnecessary pings to the API.
|
|
165
|
+
- **Diagnostic Hints**: Automatic detection of missing `/v1` in URLs or missing `sk-` in keys provides immediate developer feedback without manual debugging.
|
|
166
|
+
- **Nuclear Reset**: Added a safety valve for forgotten passwords, allowing users to wipe encrypted keys and re-configure without losing app history.
|