enterprise-ai-sdk
Enterprise AI SDK — TypeScript / Node.js
Reference implementation dari Enterprise AI SDK. Dokumen ini adalah panduan lengkap stack TS/Node: instalasi, konfigurasi, seluruh fitur, catatan operasional produksi, dan status verifikasi.
Referensi API lengkap per-method:
docs/public-api.md
(disertakan dalam paket; tautan disajikan via CDN unpkg — juga tersedia di
node_modules/enterprise-ai-sdk/docs/public-api.md setelah install).
Catatan: npmjs.com tidak mendukung tautan relatif ke berkas paket (jadi tautan mengarah ke unpkg). Tautan aktif setelah versi yang menyertakan
docs/public-api.md(≥ 0.1.1) ter-publish.
Daftar Isi
- Kebutuhan
- Instalasi & optional dependencies
- Mulai cepat
- Konfigurasi 3 lapis
- Provider
- Tools + discovery + permission
- Identity
- Session, Memory, Knowledge, Prompt
- Feedback, Learning, Local Provider (FAQ cache)
- Storage
- Error handling
- Catatan operasional produksi
- Status verifikasi & checklist produksi
- Skrip pengembangan
1. Kebutuhan
- Node.js ≥ 22 (ESM).
- Package manager: pnpm (repo memakai workspace pnpm).
2. Instalasi & optional dependencies
SDK inti tidak punya dependency runtime wajib — semua provider SDK, driver
DB, dan library retrieval bersifat optionalDependencies. Pasang HANYA
yang kamu pakai. Bila fitur dipakai tanpa package-nya terpasang, SDK melempar
error jelas yang menyebut package mana harus di-install (bukan crash misterius).
| Fitur | Package yang perlu di-install |
|---|---|
| Provider DeepSeek / OpenAI (kompatibel) | openai |
| Provider Anthropic | @anthropic-ai/sdk |
| Provider Google | @google/genai |
| Knowledge / Local Provider / rerank (embedding lokal) | @huggingface/transformers |
| Storage SQLite (default zero-config) | better-sqlite3 |
| Storage PostgreSQL | pg |
| Storage MySQL | mysql2 |
| Storage MongoDB | mongodb |
Contoh (DeepSeek + SQLite + knowledge):
pnpm add enterprise-ai-sdk openai better-sqlite3 @huggingface/transformers
apiKey via .env (JANGAN di-commit): DEEPSEEK_API_KEY, OPENAI_API_KEY,
ANTHROPIC_API_KEY, GOOGLE_API_KEY.
3. Mulai cepat
Facade statis (boot otomatis dari eai.config.json + .env):
import { AI } from 'enterprise-ai-sdk';
const res = await AI.chat('Halo, siapa kamu?');
console.log(res.getFinalMessage());
Instance eksplisit (multi-config / DI / test):
const sdk = await AI.create({
provider: { defaultProvider: 'deepseek', defaultModel: 'deepseek-v4-pro' },
providers: { deepseek: { apiKey: process.env.DEEPSEEK_API_KEY } },
});
const res = await sdk.chat('Halo');
4. Konfigurasi 3 lapis
| Lapis | Cara | Scope |
|---|---|---|
| 1 Global | AI.create / AI.configure / eai.config.json / env |
Lifetime |
| 2 Session | sdk.setConfig(partial) |
Sisa lifetime (provider/tool tetap) |
| 3 Per-call | sdk.use('x').model('m').temperature(0.2).session('s').as({userId}).chat(...) |
1 panggilan, auto-reset |
Precedence: Lapis 3 > 2 > programmatic > file > env > default. Contoh file lengkap ada di #4.2; tabel field per-item: docs/api/public-api.md #2.
4.1 Config file & environment
- File: SDK membaca
eai.config.jsondari cwd aplikasi (opsional — SDK jalan tanpa file config, cukupAI.create({...})). - Override path file: set env
EAI_CONFIG_PATH(absolut, atau relatif terhadap cwd) untuk memakai file di lokasi lain. - API key: JANGAN taruh di file config. Pakai environment:
DEEPSEEK_API_KEY,OPENAI_API_KEY,ANTHROPIC_API_KEY,GOOGLE_API_KEY(pola<PROVIDER-ID>_API_KEY). Nilai env menang atas file untuk apiKey.
Paket npm tidak menyertakan file contoh (hanya
dist). Buat sendirieai.config.jsondi root project-mu — salin templat di bawah, ubah seperlunya. Semua field opsional; yang tidak diisi memakai default.
4.2 Contoh eai.config.json (LENGKAP — nilai = default)
{
"namespace": null,
"provider": { "defaultProvider": "deepseek", "defaultModel": "deepseek-v4-pro", "allowedProviders": [] },
"providers": { "deepseek": { "model": "deepseek-v4-pro", "baseUrl": null, "temperature": null, "maxTokens": null } },
"timeout": { "requestTimeoutMs": 30000, "providerTimeoutMs": 25000 },
"retry": { "enabled": false, "maxRetries": 2, "retryDelayMs": 1000 },
"fallback": { "enabled": false, "fallbackProviders": [] },
"streaming":{ "enabled": false },
"logging": { "enabled": true, "level": "info", "redactionEnabled": true },
"cost": { "trackingEnabled": true, "pricing": null },
"security": { "redactionEnabled": true, "promptDebuggingEnabled": false },
"storage": { "enabled": false, "defaultConnection": "sqlite",
"databases": { "sqlite": { "adapter": "sqlite", "connectionString": null, "prefix": "eai_" } } },
"session": { "enabled": false, "maxMessages": 20, "fields": {} },
"memory": { "enabled": false, "maxEntries": 100 },
"knowledge":{ "enabled": false, "maxEntries": 500 },
"learning": { "enabled": false, "autoRecord": false },
"cache": { "enabled": false, "ttlMs": 300000, "maxEntries": 500 },
"embedding":{ "model": "Xenova/multilingual-e5-small", "threshold": 0.8, "scanLimit": 500, "candidateLimit": 100 },
"rerank": { "model": "Xenova/bge-reranker-base", "threshold": 0.1, "topK": 10 },
"prompt": { "systemPrompt": null },
"tools": { "autoExec": true, "maxDiscoveryIterations": 1 },
"localProvider": { "enabled": false, "similarityThreshold": 0.9, "rerankThreshold": 0.3, "scanLimit": 500 }
}
5. Provider
Bawaan (auto-register bila apiKey ter-resolve): deepseek, openai,
anthropic, google. Kustom: sdk.registerProvider(id, adapter).
await sdk.use('anthropic').chat('...'); // per-call
const sdk2 = await AI.create({ provider: { defaultProvider: 'openai' }, providers: { openai: { apiKey: '...' } } });
baseUrl per provider: tiap provider punya default endpoint; override via
providers.<id>.baseUrl (proxy/gateway/Azure/self-hosted). Berlaku di
AI.create maupun setConfig. Detail + tabel default: docs/public-api.md.
await AI.create({ providers: { openai: { apiKey: '...', baseUrl: 'https://openrouter.ai/api/v1' } } });
6. Tools + discovery + permission
sdk.registerTool({
name: 'getSalary',
description: 'Ambil gaji karyawan. WAJIB untuk pertanyaan gaji.',
placeholders: ['salary_info'],
roles: ['hr'], // izin berbasis role (opsional)
handler: async () => ({ success: true, data: { salary_info: 'Rp 15.000.000' } }),
});
// autoExec default true → SDK eksekusi tool + isi placeholder otomatis:
const res = await sdk.as({ userId: 'u1', roles: ['hr'] }).chat('Berapa gaji saya?');
console.log(res.getFinalMessage()); // "{salary_info}" sudah terisi
- Discovery (meta-tools): schema tool tak dijejalkan ke tiap prompt; SDK
menawarkan
listTools, menyaring (embed+rerank), lalu menyuntik yang relevan. - Permission:
roles:[]= publik; non-kosong → identity wajib punya ≥1 role. - autoExec=false: aplikasi panggil
res.executeTools()lalu (opsional)res.saveToHistory().
Reliabilitas discovery — lihat #12.
7. Identity
SDK tidak melakukan authentication — aplikasi menyetel identity tervalidasi.
sdk.setIdentity({ userId: 'u-1', displayName: 'John Doe', roles: ['admin'] }); // default
await sdk.as({ userId: 'u-2', roles: ['hr'] }).chat('...'); // per-call
Resolusi: per-call as() → default setIdentity → anonymous. roles = basis
permission tool.
8. Session, Memory, Knowledge, Prompt
// Session (butuh session.enabled):
await sdk.session('sesi-42').chat('Namaku John Doe');
await sdk.session('sesi-42').chat('Siapa namaku?'); // → "John Doe"
// Memory PER-USER (butuh memory.enabled + identity non-anonim):
sdk.setIdentity({ userId: 'u-1' });
await sdk.remember('User suka jawaban singkat'); // anonim tanpa scope → TIDAK disimpan
// Knowledge (butuh knowledge.enabled; retrieval embed→rerank):
await sdk.addKnowledge({ title: 'Jam kerja', content: 'Kantor buka 09.00-17.00 WIB.' });
// Prompt global (persona/aturan, selalu dibawa):
sdk.setPrompt('Kamu asisten HR. Jawab dalam Bahasa Indonesia.');
9. Feedback, Learning, Local Provider (FAQ cache)
AI menandai jawaban cacheable (stabil). Hanya cacheable:true yang direkam
ke learning. Feedback diberikan admin, asinkron:
const items = await sdk.listHistory(20);
await sdk.historyFeedback(items[0].id, 'positive'); // positive|neutral|negative
Local Provider (FAQ cache lokal-first) menjawab dari learning ber-feedback SEBELUM memanggil provider berbayar (hemat biaya):
const sdk = await AI.create({
storage: { enabled: true }, learning: { enabled: true, autoRecord: true },
localProvider: { enabled: true }, // WAJIB storage.enabled
});
const res = await sdk.chat('berapa hari cuti tahunan');
res.usedLocalProvider(); // true bila dijawab dari cache
Seleksi kandidat: positive dulu (acak bila >1, sengaja — agar terasa manusiawi), neutral fallback, negative/null tak pernah.
Batasan Local Provider: untuk FAQ stabil, bukan pemahaman bahasa umum. Cache kosong sampai admin memberi feedback. Threshold tinggi (minim false-positive) → recall lebih rendah. Jawaban terhitung/promo time-limited otomatis
cacheable:false. Detail: public-api.md #8.
9b. Vision (analisis gambar)
Analisis gambar oleh model multimodal. Provider: OpenAI (diverifikasi), Anthropic, Google (kode siap; DeepSeek dukungan vision terbatas). Tiga tipe input — SDK menyesuaikan format per provider:
const res = await sdk.vision('Bacakan nominal & nomor referensi.', [
{ type: 'file', path: './bukti-transfer.jpg' }, // dirFile
// { type: 'url', url: 'https://…/receipt.png' }, // di-fetch SDK
// { type: 'base64', data: 'iVBOR…', mimeType: 'image/png' },
]);
console.log(res.getFinalMessage());
Output terstandar via fields — samakan nama field lintas format (mis.
jumlah/amount → satu nama kanonik). Model mengisi data.payload pakai nama
kamu persis; dalam session, payload otomatis tersimpan ke session data (§9c):
const res = await sdk.session('trx-42').vision('Baca bukti transfer.',
[{ type: 'file', path: './bukti.jpg' }],
{ fields: { pengirim: 'nama pengirim', nominal: 'nominal (angka)', noRef: 'no. referensi' } },
);
res.raw.data.payload; // → { pengirim:'Budi', nominal:'170000', noRef:'FT…' }
Keputusan & risiko ada pada aplikasi — SDK hanya menyiapkan alat:
- Gambar BUKAN bukti final (bisa dipalsukan). Pakai vision untuk MEMBACA; verifikasi kebenaran ke sistem asli (mis. lookup nomor referensi ke gateway).
- Vision bisa salah baca (mirip OCR). Minta field terstruktur lalu cocokkan di aplikasi; jangan andalkan interpretasi bebas untuk keputusan penting.
Detail + tabel tipe input: public-api.md #12.
9c. Session Data (fakta terstruktur per-session)
Beda dari history (pesan, dipotong maxMessages), session data = fakta
mesin (nama, nominal, hasil vision) yang selalu disuntik penuh ke prompt —
tak pernah terpotong selama session hidup. Akumulatif; kunci sessionId.
Isi otomatis dari chat & vision via skema session-global setSessionFields:
selama session aktif, tiap request mengekstrak field ke payload → auto-store
(dedup, record identik dibuang).
sdk.setSessionFields({ userId: 'user yang dicek', tanggal: 'tanggal (YYYY-MM-DD)' });
// User chatting biasa: "cek transaksi dian tanggal 2026-04-02"
// → tersimpan { userId:'dian', tanggal:'2026-04-02' }. "cek anto 2026-05-02" → record ke-2.
Di prompt, data tampil dua bentuk — per-field unik (userId: dian, anto) +
kombinasi records — sehingga AI bisa merekomendasikan pilihan yang sudah
pernah diproses ("mau cek dian 2026-04-02 atau anto 2026-05-02?").
Isi manual (WAJIB .session(id), tanpa itu → session_id_required):
await sdk.session('trx-42').rememberData({ pengirim: 'Budi', bank: 'BCA' });
const facts = await sdk.session('trx-42').sessionData(); // baca semua
Data hanya disuntik ke prompt (bukan dilempar ke tool). Belum ada TTL — bertahan sampai storage di-clear.
Hapus session. sessionId menyatukan history + session data + pending-tool.
clearSession(id) menghapus ketiganya sekaligus (idempoten):
await sdk.clearSession('trx-42'); // history + session data + pending-tool → hilang
Detail + tabel perbandingan: public-api.md #7a.
10. Storage
Multi-connection gaya Laravel:
storage: {
enabled: true,
defaultConnection: 'main',
databases: {
main: { adapter: 'postgres', connectionString: 'postgres://…', prefix: 'eai_' },
},
}
storage.enabled:false → in-memory ephemeral. Adapter: sqlite (default,
fallback ./.eai/llm-storage.sqlite), postgres, mysql, mongodb — install
driver terkait (lihat #2).
pgvector (opsional, PostgreSQL). Bila ekstensi vector terpasang, recall
cosine knowledge & FAQ cache dihitung di database (<=>) — otomatis, tanpa
migration. Aktifkan sekali: CREATE EXTENSION IF NOT EXISTS vector; (SDK juga
mencobanya saat init). Tanpa pgvector → tetap jalan (fetch + cosine). Detail:
public-api.md #7.
Penamaan:
MemoryStorageAdapter= adapter storage in-memory (RAM), BEDA dari subsystem memory (sdk.remember).
10b. Multi-tenant (namespace + berbagi resource)
Pola sah: satu instance SDK per tenant (karena setPrompt/setSessionFields/
baseUrl di level instance), sering berbagi satu database. Tiga penopang:
namespace— setsdk.setNamespace('site-42')(atau confignamespace): di-fold ke scope-key semua subsistem storage (memory/session/session-data/ knowledge/learning) → tenant berbagi tabel tak saling melihat data.null= perilaku lama.- Model retrieval di-share otomatis (berkunci identitas model) → N instance
model sama = 1 sesi ONNX di RAM, bukan N × ~400 MB.
setConfigganti model kini berlaku saat runtime. - Pool koneksi di-share otomatis (berkunci
adapter|connectionString|prefix) → instance koneksi sama = 1 pool (hindari kehabisanmax_connections). Refcount; graceful shutdown:import { closeAllStorage } from 'enterprise-ai-sdk'.
Cache response, ConfigState, ToolRegistry, provider registry tetap
per-instance (sengaja). Detail: public-api.md #13.
11. Error handling
chat() TIDAK melempar untuk kegagalan runtime — selalu envelope. Cek
res.status; detail res.raw.error (code, category, retryable, …).
Kategori: validation, configuration, provider, timeout, rate_limit,
tool, runtime, internal. Yang MELEMPAR: setup invalid (AI.create/
setConfig), registerTool invalid, pemakaian salah executeTools/
saveToHistory/recordToLearning.
12. Catatan operasional produksi
12.1 Cold-start model lokal
Embedding & rerank (@huggingface/transformers) mengunduh + memuat model
saat pemakaian PERTAMA (puluhan detik + memori). Request knowledge/
localProvider pertama lambat; berikutnya cepat (model ter-cache di proses).
- Rekomendasi: panggil
await sdk.warmup()(atauAI.warmup()) sekali saat boot aplikasi — preload model embedding+rerank sebelum melayani trafik, sehingga request pertama tidak lambat.const sdk = await AI.create({ /* ... */ }); await sdk.warmup(); // model siap - Ini hanya latensi hit-pertama; wajar untuk deployment yang di-test sebelum go-live.
12.2 Reliabilitas tool discovery (meta-tools)
Discovery adalah loop agentic: model harus (a) meminta listTools, lalu (b)
memilih tool + params yang benar. Mekaniknya benar & deterministik di dev, TAPI
bergantung kepatuhan model saat itu — model yang lambat/kurang patuh bisa
gagal memicu tool atau timeout di tengah.
- Cara aplikasi menangani:
- Aktifkan
retry(retry.enabled: true) untuk request ber-tool. - Selalu cek
res.hasAction()— jangan asumsikan tool pasti terpilih. - Sediakan fallback ketika tool tak terpanggil (mis. minta user memperjelas).
- Naikkan
timeout.providerTimeoutMsuntuk alur discovery (2 panggilan). tools.maxDiscoveryIterations(default 1) menjaga dari loop.
- Aktifkan
- Alternatif bila butuh determinisme tinggi: model lebih patuh, atau strategi native function-calling (lebih boros token, mengikat ke provider).
12.3 Skala retrieval
Tanpa vector query native, learning/knowledge besar = fetch semua kandidat
- cosine di Node tiap query (O(n); vektor sudah di-precompute saat tulis, jadi tak ada re-embed). Aman untuk kecil–menengah; ada plafon skala. Native pgvector/Atlas ditunda ke slice terpisah.
13. Status verifikasi & checklist produksi
Terverifikasi terhadap backend nyata:
- DeepSeek (chat, resiliency, tools, subsystem)
- Storage SQLite / PostgreSQL / MySQL / MongoDB (CRUD)
- Retrieval embed/rerank lokal, feedback, Local Provider, identity, permission
- Adapter Anthropic — terverifikasi sampai batas API (chat penuh butuh kredit API)
Belum diuji real (butuh kredensial): provider OpenAI & Google (execute()).
Checklist sebelum production:
- Smoke test provider yang dipakai dengan API key + kredit nyata.
- Pasang driver DB yang dipakai (optional dep).
- Warmup model lokal saat boot bila pakai knowledge/localProvider.
- Aktifkan
retryuntuk alur ber-tool + tanganihasAction()false. - Tetapkan
license, versi rilis, CI (belum disiapkan).
TODO by design: capability stream/reason/embedding/vision/ocr (stub),
vector query native, telemetry backend, LocalProviderAdapter sebagai provider
'local'.
14. Skrip pengembangan
pnpm build # tsc → dist/
pnpm typecheck # tsc --noEmit (source)
pnpm typecheck:test # typecheck test
pnpm test # vitest (real DeepSeek bila DEEPSEEK_API_KEY ada; sisanya di-skip)
pnpm test:coverage # + coverage
pnpm lint # eslint
Test REAL terhadap provider/DB nyata aktif otomatis bila env kredensial diisi
(mis. DEEPSEEK_API_KEY, POSTGRES_TEST_URL, MYSQL_TEST_URL, MONGODB_TEST_URL).
15. Publikasi (npm publik)
Paket ini di-publish publik ke npm (nama unscoped enterprise-ai-sdk,
lisensi MIT, publishConfig.access: "public"). prepublishOnly menjalankan
typecheck + lint + build otomatis sebelum publish; hanya dist/ + README.md
LICENSEyang masuk tarball.
# 1. Login npm (sekali):
npm login
npm whoami # verifikasi ter-autentikasi
# 2. Publish (dari implementations/typescript-node/):
npm publish
# Rilis berikutnya: naikkan versi dulu
npm version patch # 0.1.0 → 0.1.1 (atau minor/major)
npm publish
ESM-only — consumer harus mendukung ESM ("type": "module" atau import dinamis).
Referensi API lengkap ada di docs/public-api.md
(disertakan dalam paket). Dokumen desain (ADR & review per-slice) berada di
repositori sumber (privat/internal).