@vibe-bot/sdk
v0.1.1
Published
Zero-dependency, OpenAI-compatible TypeScript SDK for VibeBot.
Maintainers
Readme
@vibe-bot/sdk
Tiny, zero-dependency TypeScript SDK for the VibeBot API. Wire-compatible with OpenAI Chat Completions, so anything that speaks OpenAI speaks VibeBot.
- 0 runtime dependencies — standard web APIs only (
fetch,ReadableStream,TextDecoder,AbortSignal) - Node 18+, browsers, Cloudflare Workers / Vercel Edge
- ESM + CJS dual build with
.d.ts - Streaming via
for await, automatic retries, typed errors
Install
npm i @vibe-bot/sdkOne line
import { VibeBot } from '@vibe-bot/sdk';
const vb = new VibeBot({ apiKey: process.env.VIBEBOT_KEY });
console.log(await vb.ask('agt_9f2c', '환불 되나요?'));
// → "네, 배송 후 7일 이내면 됩니다."Chat completions
const res = await vb.chat.completions.create({
model: 'agt_9f2c', // the agentId goes in `model`
messages: [{ role: 'user', content: '환불 되나요?' }],
temperature: 0.3,
user: 'sess_abc', // conversation/session id
});
res.choices[0].message.content;
res.vibebot?.sources; // [{ id, title, url, score }]
res.vibebot?.confidence; // 0.91
res.vibebot?.escalate; // falseStreaming
stream: true returns an async iterable of ChatCompletionChunk.
The vibebot extension (sources, confidence) rides on the final chunk.
const stream = await vb.chat.completions.create({
model: 'agt_9f2c',
messages: [{ role: 'user', content: '환불 되나요?' }],
stream: true,
});
let sources;
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
if (chunk.vibebot?.sources) sources = chunk.vibebot.sources;
}
// stop early
stream.abort();Widget bootstrap
const cfg = await vb.agents.get('agt_9f2c');
// { id, name, greeting, suggestions, theme: { accent, position, radius }, branding }GET /v1/agents/:id is public — no API key needed. Omit apiKey and the SDK runs in
public mode (no Authorization header); the server authorises by Origin.
Management API
Create agents and feed them sources from code — useful for refreshing content in CI, or spinning up one agent per customer.
These calls require an API key. Unlike chat, they are never callable without one: a key exposed in a browser would let anyone delete the agent. Keep them server-side.
const vb = new VibeBot({ apiKey: process.env.VIBEBOT_KEY });
const agent = await vb.agents.create({ name: '문서봇', persona: '짧게 답한다.' });
// A URL crawls same-host links (up to 8 pages) unless you pass `crawl: false`
await vb.agents.sources.create(agent.id, { url: 'https://mysite.com' });
await vb.agents.sources.create(agent.id, { kind: 'text', title: '환불정책', text: '…' });
// What could it not answer?
const log = await vb.agents.conversations(agent.id, { limit: 50 });
log.filter((c) => c.escalated).forEach((c) => console.log(c.question));| Method | Endpoint | |
|---|---|---|
| agents.list() | GET /v1/agents | Every agent the key's owner has |
| agents.create(body) | POST /v1/agents | Enforces the plan's agent limit |
| agents.get(id) | GET /v1/agents/:id | Public bootstrap — no key needed |
| agents.update(id, body) | PATCH /v1/agents/:id | |
| agents.delete(id) | DELETE /v1/agents/:id | |
| agents.sources.list(id) | GET /v1/agents/:id/sources | |
| agents.sources.create(id, body) | POST /v1/agents/:id/sources | Enforces the plan's source limit |
| agents.sources.delete(id, srcId) | DELETE /v1/agents/:id/sources/:sourceId | |
| agents.conversations(id, params) | GET /v1/agents/:id/conversations | |
Adding a URL can create several sources at once, so the result is a union rather than a flat array. That is deliberate: flattening would hide the fact that one call just consumed several of your plan's source slots.
const res = await vb.agents.sources.create(id, { url: 'https://mysite.com' });
// { sources: Source[], count: number } ← URL
// Source ← textSomeone else's agent always answers 404, never 403 — we don't confirm that an id exists.
Errors
Everything throws VibeBotError, with subclasses per status.
import { VibeBotError, RateLimitError, NotFoundError } from '@vibe-bot/sdk';
try {
await vb.ask('agt_nope', 'hi');
} catch (err) {
if (err instanceof NotFoundError) { /* err.status 404, err.code 'agent_not_found' */ }
if (err instanceof VibeBotError) console.error(err.status, err.code, err.type, err.message);
}| HTTP | class | code | type |
|---|---|---|---|
| 400 | BadRequestError | invalid_request_error | invalid_request_error |
| 401 | AuthenticationError | invalid_api_key | authentication_error |
| 403 | PermissionDeniedError | — | permission_error |
| 404 | NotFoundError | agent_not_found | invalid_request_error |
| 429 | RateLimitError | rate_limit_exceeded | rate_limit_error |
| 5xx | InternalServerError | internal_error | api_error |
| — | APIConnectionError / APIConnectionTimeoutError | — | — |
| — | APIUserAbortError | — | — |
Server-provided code/type always win; the table is the fallback.
Retries
429, 408, 409 and 5xx are retried with exponential backoff + jitter (2 retries by default).
A Retry-After header (seconds or HTTP-date) overrides the computed delay.
4xx (other than those) and user aborts are never retried.
const vb = new VibeBot({ maxRetries: 5 });
await vb.ask('agt_9f2c', 'hi', { maxRetries: 0 }); // per-request overrideAbort & timeout
const ac = new AbortController();
setTimeout(() => ac.abort(), 2000);
await vb.chat.completions.create(params, { signal: ac.signal }); // → APIUserAbortError
await vb.chat.completions.create(params, { timeout: 5000 }); // → APIConnectionTimeoutErrorUse the official openai package instead
The endpoint is wire-compatible, so this works — and is covered by our test suite:
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: process.env.VIBEBOT_KEY,
baseURL: 'https://vibebot.store/v1',
});
const res = await openai.chat.completions.create({
model: 'agt_9f2c',
messages: [{ role: 'user', content: '환불 되나요?' }],
});
// res.vibebot?.sources is passed through untouchedOptions
new VibeBot(options)
| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | string | — | Secret key (vb_sk_…). Omit for public/widget mode. |
| baseURL | string | http://localhost:3000/v1 | API root. Trailing slashes are trimmed. |
| maxRetries | number | 2 | Retries on 429/408/409/5xx and network errors. |
| timeout | number | 60000 | Per-request timeout in ms. 0 disables. |
| defaultHeaders | Record<string,string> | {} | Headers added to every request. |
| fetch | (url, init) => Promise<Response> | global fetch | Injectable fetch — for tests, proxies, custom runtimes. |
| retryDelayMs | number | 500 | Base backoff delay. Doubles each attempt, ±25% jitter. |
| maxRetryDelayMs | number | 8000 | Ceiling for a single backoff sleep. |
Request options (2nd argument of create / agents.get / ask)
| Option | Type | Description |
|---|---|---|
| signal | AbortSignal | Cancels the request (and any active stream). |
| timeout | number | Overrides the client timeout for this call. |
| maxRetries | number | Overrides the client retry count for this call. |
| headers | Record<string,string> | Extra headers, merged over the defaults. |
create params
| Field | Type | Required | Description |
|---|---|---|---|
| model | string | ✓ | The agentId, e.g. agt_9f2c. |
| messages | ChatCompletionMessageParam[] | ✓ | role: system | user | assistant. |
| stream | boolean | | true returns Stream<ChatCompletionChunk>. |
| temperature | number | | |
| user | string | | Conversation/session identifier. |
Exports
VibeBot (also default), Stream, SSEDecoder, LineDecoder, DEFAULT_BASE_URL,
all error classes, and the types ChatCompletion, ChatCompletionChunk,
ChatCompletionMessageParam, ChatCompletionCreateParams*, AgentConfig,
VibeBotSource, VibeBotExtension, ClientOptions, RequestOptions, FetchLike.
Development
npm run build # dist/esm + dist/cjs + .d.ts
npm test # node --test (no external runner)Every test runs against an injected fetch — no server required.
