@bandito-ai/sdk 0.1.7
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 +162 -0
- package/dist/index.d.mts +145 -0
- package/dist/index.d.ts +145 -0
- package/dist/index.js +640 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +597 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +53 -0
- package/wasm/bandito_engine.d.ts +46 -0
- package/wasm/bandito_engine.js +283 -0
- package/wasm/bandito_engine_bg.wasm +0 -0
- package/wasm/bandito_engine_bg.wasm.d.ts +19 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/engine.ts","../src/models.ts","../src/config.ts","../src/http.ts","../src/store.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * BanditoClient — main orchestrator for the JS/TS SDK.\n *\n * Mirrors the Python SDK's sync-first design:\n * - pull() is synchronous (WASM math, <1ms)\n * - connect(), grade(), sync(), close() are async (HTTP I/O)\n * - update() is synchronous (SQLite write + fire-and-forget flush)\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { initWasm, createEngine, updateEngine, type BanditEngine, type EnginePullResult } from \"./engine.js\";\nimport {\n type Arm,\n type PullResult,\n type BanditCache,\n type ArmWire,\n createArm,\n createPullResult,\n} from \"./models.js\";\nimport { loadConfig, DEFAULT_BASE_URL } from \"./config.js\";\nimport { BanditoHTTP } from \"./http.js\";\nimport { EventStore, type EventPayload } from \"./store.js\";\nimport { prepareCloudPayload } from \"./worker.js\";\n\nconst DEFAULT_STORE_PATH = path.join(os.homedir(), \".bandito\", \"events.db\");\nconst MAX_EVENT_RETRIES = 5;\n\nexport interface ClientOptions {\n apiKey?: string;\n baseUrl?: string;\n storePath?: string;\n dataStorage?: string;\n}\n\nexport interface PullOptions {\n query?: string;\n exclude?: number[];\n}\n\nexport interface UpdateOptions {\n queryText?: string;\n response?: string | Record<string, unknown>;\n reward?: number;\n cost?: number;\n latency?: number;\n inputTokens?: number;\n outputTokens?: number;\n segment?: Record<string, string>;\n failed?: boolean;\n}\n\nexport class BanditoClient {\n private apiKey: string | undefined;\n private baseUrl: string | undefined;\n private storePath: string | undefined;\n private dataStorageArg: string | undefined;\n private dataStorage: string;\n\n private http: BanditoHTTP | null = null;\n private store: EventStore | null = null;\n private engines: Map<string, BanditEngine> = new Map();\n private bandits: Map<string, BanditCache> = new Map();\n private connected = false;\n private flushInterval: ReturnType<typeof setInterval> | null = null;\n private flushInProgress = false;\n private deadUuids: Set<string> = new Set();\n private retryCounts: Map<string, number> = new Map();\n\n constructor(options: ClientOptions = {}) {\n this.apiKey = options.apiKey;\n this.baseUrl = options.baseUrl;\n this.storePath = options.storePath;\n this.dataStorageArg = options.dataStorage;\n this.dataStorage = options.dataStorage ?? \"local\";\n }\n\n /**\n * Bootstrap: authenticate and hydrate in-memory state from cloud.\n *\n * Resolves config from: constructor args → env vars → ~/.bandito/config.toml.\n * Initializes WASM, creates HTTP client, SQLite store, fetches full state.\n */\n async connect(): Promise<void> {\n // Tear down previous connection if reconnecting\n if (this.connected) {\n await this.close();\n }\n\n // Init WASM (loads .wasm binary once)\n await initWasm();\n\n // Resolve config\n const config = loadConfig();\n const apiKey = this.apiKey ?? config.apiKey;\n if (!apiKey) {\n throw new Error(\n \"apiKey required — pass it to constructor, set BANDITO_API_KEY, \" +\n \"or run `bandito signup`\",\n );\n }\n\n const baseUrl = this.baseUrl ?? config.baseUrl;\n if (!this.dataStorageArg) {\n this.dataStorage = config.dataStorage;\n }\n\n this.http = new BanditoHTTP(baseUrl, apiKey);\n const storePath = this.storePath ?? DEFAULT_STORE_PATH;\n if (storePath !== \":memory:\") {\n const dir = path.dirname(storePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n }\n this.store = new EventStore(storePath);\n\n // Bootstrap: fetch state, hydrate cache, flush pending\n try {\n const data = await this.http.connect();\n this.applySync(data);\n\n // Reset retry state\n this.deadUuids.clear();\n this.retryCounts.clear();\n\n // Flush pending events from previous crash\n await this.flushPending();\n\n // Start periodic flush (every 30s)\n this.flushInterval = setInterval(() => {\n this.flushPending().catch(() => {});\n }, 30_000);\n\n this.connected = true;\n } catch (err) {\n this.store?.close();\n this.store = null;\n this.http = null;\n throw err;\n }\n }\n\n /**\n * Local Thompson Sampling decision. Synchronous, <1ms, no network.\n */\n pull(banditName: string, options: PullOptions = {}): PullResult {\n this.ensureConnected();\n\n const cache = this.bandits.get(banditName);\n if (!cache) {\n const available = [...this.bandits.keys()];\n throw new Error(\n `Unknown bandit '${banditName}'. Available: [${available.join(\", \")}]`,\n );\n }\n\n if (cache.arms.length === 0) {\n throw new Error(`Bandit '${banditName}' has no active arms`);\n }\n\n const engine = this.engines.get(banditName)!;\n const queryLength = options.query?.length ?? undefined;\n const excludeIds = options.exclude ? Int32Array.from(options.exclude) : undefined;\n\n const resultJson = engine.pull(queryLength, excludeIds);\n const raw: EnginePullResult = JSON.parse(resultJson);\n\n // Look up the winning arm from our cached active arms\n const winnerArm = cache.arms.find((a) => a.armId === raw.arm_id);\n if (!winnerArm) {\n throw new Error(\n `Engine selected arm ${raw.arm_id} but it's not in active arm cache for \"${banditName}\". ` +\n \"This is likely a bug — please report it at https://github.com/bandito-ai/bandito/issues\",\n );\n }\n\n return createPullResult({\n arm: winnerArm,\n eventId: randomUUID(),\n banditId: cache.banditId,\n banditName,\n scores: raw.scores,\n pullTime: performance.now(),\n });\n }\n\n /**\n * Record an LLM call outcome. Writes to SQLite first (crash-safe),\n * then fires off a non-blocking flush to cloud.\n */\n update(pullResult: PullResult, options: UpdateOptions = {}): void {\n this.ensureConnected();\n\n let reward = options.reward;\n if (options.failed && reward == null) {\n reward = 0.0;\n }\n\n // Auto-calculate latency from pull timestamp\n let latency = options.latency;\n if (latency == null && pullResult._pullTime > 0) {\n latency = performance.now() - pullResult._pullTime;\n }\n\n // Build event payload (snake_case for wire format)\n const event: EventPayload = {\n local_event_uuid: pullResult.eventId,\n bandit_id: pullResult.banditId,\n arm_id: pullResult.arm.armId,\n model_name: pullResult.arm.modelName,\n model_provider: pullResult.arm.modelProvider,\n };\n\n if (options.queryText != null) {\n (event as Record<string, unknown>).query_text = options.queryText;\n }\n if (options.response != null) {\n (event as Record<string, unknown>).response =\n typeof options.response === \"string\"\n ? { response: options.response }\n : options.response;\n }\n if (reward != null) {\n (event as Record<string, unknown>).early_reward = reward;\n }\n if (options.cost != null) {\n (event as Record<string, unknown>).cost = options.cost;\n }\n if (latency != null) {\n (event as Record<string, unknown>).latency = latency;\n }\n if (options.inputTokens != null) {\n (event as Record<string, unknown>).input_tokens = options.inputTokens;\n }\n if (options.outputTokens != null) {\n (event as Record<string, unknown>).output_tokens = options.outputTokens;\n }\n if (options.segment != null) {\n (event as Record<string, unknown>).segment = options.segment;\n }\n if (options.failed) {\n (event as Record<string, unknown>).run_error = true;\n }\n\n // Write to SQLite WAL first — survives crashes\n this.store!.push(event);\n\n // Fire-and-forget flush (errors logged inside flushPending)\n this.flushPending().catch(() => {});\n }\n\n /**\n * Send a human grade for an existing event. Async (HTTP).\n */\n async grade(eventId: string, grade: number): Promise<void> {\n this.ensureConnected();\n await this.http!.submitGrade(eventId, grade);\n }\n\n /**\n * Explicit state refresh from cloud.\n */\n async sync(): Promise<void> {\n this.ensureConnected();\n const data = await this.http!.heartbeat();\n\n const prevBandits = new Map(this.bandits);\n const prevEngines = new Map(this.engines);\n try {\n this.applySync(data);\n } catch (err) {\n // Rollback on malformed response — keep last-known-good state\n this.bandits = prevBandits;\n this.engines = prevEngines;\n console.warn(\"[bandito] Sync response malformed — keeping last-known-good state\", err);\n }\n }\n\n /**\n * Shut down: clear interval, flush remaining events, close connections.\n */\n async close(): Promise<void> {\n if (this.flushInterval) {\n clearInterval(this.flushInterval);\n this.flushInterval = null;\n }\n\n // Final flush\n if (this.store && this.http) {\n await this.flushPending();\n }\n\n this.store?.close();\n this.store = null;\n this.http = null;\n this.engines.clear();\n this.bandits.clear();\n this.connected = false;\n }\n\n // --- Internal ---\n\n private ensureConnected(): void {\n if (!this.connected) {\n throw new Error(\"Not connected — call connect() first\");\n }\n }\n\n private applySync(data: Record<string, unknown>): void {\n const banditsData = (data.bandits ?? []) as Record<string, unknown>[];\n\n const newBandits = new Map<string, BanditCache>();\n const newEngines = new Map<string, BanditEngine>();\n\n for (const b of banditsData) {\n const arms = (b.arms ?? []) as ArmWire[];\n if (arms.length === 0) continue;\n\n const activeArms: Arm[] = arms\n .filter((a) => a.is_active)\n .map((a) => createArm(a));\n\n const name = b.name as string;\n const cache: BanditCache = {\n banditId: Number(b.bandit_id),\n name,\n arms: activeArms,\n armWire: arms,\n optimizationMode: (b.optimization_mode as string) ?? \"base\",\n avgLatencyLastN: b.avg_latency_last_n as number | null,\n budget: b.budget as number | null,\n totalCost: b.total_cost as number | null,\n };\n\n newBandits.set(name, cache);\n\n // Reuse existing engine (preserves RNG state) or create new one\n const existingEngine = this.engines.get(name);\n const banditJson = JSON.stringify(b);\n if (existingEngine) {\n updateEngine(existingEngine, banditJson);\n newEngines.set(name, existingEngine);\n } else {\n newEngines.set(name, createEngine(banditJson));\n }\n }\n\n this.bandits = newBandits;\n this.engines = newEngines;\n }\n\n private async flushPending(): Promise<void> {\n if (this.flushInProgress || !this.store || !this.http) return;\n this.flushInProgress = true;\n\n try {\n const pending = this.store.pending();\n if (pending.length === 0) return;\n\n // Filter out dead events\n const alive = this.deadUuids.size > 0\n ? pending.filter((e) => !this.deadUuids.has(e.local_event_uuid))\n : pending;\n if (alive.length === 0) return;\n\n // Prepare payload (strip metadata/text as configured)\n const payload = prepareCloudPayload(\n alive as Record<string, unknown>[],\n this.dataStorage !== \"local\",\n );\n\n const result = await this.http.ingestEvents(payload);\n\n // Parse per-event errors\n const errors = (result.errors ?? []) as {\n local_event_uuid?: string;\n reason?: string;\n }[];\n const erroredUuids = new Set(\n errors.map((e) => e.local_event_uuid).filter(Boolean) as string[],\n );\n\n // Update retry counts\n for (const uid of erroredUuids) {\n const count = (this.retryCounts.get(uid) ?? 0) + 1;\n this.retryCounts.set(uid, count);\n if (count >= MAX_EVENT_RETRIES) {\n this.deadUuids.add(uid);\n }\n }\n\n // Mark accepted events as flushed\n const flushedUuids = alive\n .map((e) => e.local_event_uuid)\n .filter((uid) => !erroredUuids.has(uid));\n if (flushedUuids.length > 0 && this.store) {\n this.store.markFlushed(flushedUuids);\n }\n } catch (err) {\n // Flush failure is non-fatal — events stay pending for next attempt\n console.warn(\"[bandito] Event flush failed — will retry\", err);\n } finally {\n this.flushInProgress = false;\n }\n }\n}\n","/**\n * Thin wrapper around the WASM engine import.\n *\n * Handles async WASM initialization (loading .wasm binary happens once)\n * and re-exports the BanditEngine constructor for the client.\n */\n\nimport type { BanditEngine as WasmBanditEngine } from \"../wasm/bandito_engine\";\n\nlet wasmModule: typeof import(\"../wasm/bandito_engine\") | null = null;\n\n/**\n * Initialize the WASM module. Must be called before creating BanditEngine instances.\n * Safe to call multiple times — only loads once.\n */\nexport async function initWasm(): Promise<void> {\n if (wasmModule) return;\n wasmModule = await import(\"../wasm/bandito_engine\");\n}\n\n/**\n * Create a BanditEngine from a sync response JSON string.\n * Requires initWasm() to have been called first.\n */\nexport function createEngine(banditJson: string): WasmBanditEngine {\n if (!wasmModule) {\n throw new Error(\"WASM not initialized — call initWasm() first\");\n }\n return new wasmModule.BanditEngine(banditJson);\n}\n\n/**\n * Update an existing BanditEngine with new sync response data.\n * Preserves RNG state (avoids the \"always picks same arm\" bug).\n */\nexport function updateEngine(engine: WasmBanditEngine, banditJson: string): void {\n engine.updateFromSync(banditJson);\n}\n\nexport type { WasmBanditEngine as BanditEngine };\n\n/**\n * Pull result parsed from engine JSON output.\n */\nexport interface EnginePullResult {\n arm_index: number;\n arm_id: number;\n scores: Record<number, number>;\n}\n","/**\n * SDK types: Arm, PullResult, and internal cache structures.\n */\n\n/** An arm returned to the user after pull(). Immutable. */\nexport interface Arm {\n readonly armId: number;\n readonly modelName: string;\n readonly modelProvider: string;\n readonly systemPrompt: string;\n readonly isPromptTemplated: boolean;\n /** Convenience alias for modelName. */\n readonly model: string;\n /** Convenience alias for systemPrompt. */\n readonly prompt: string;\n}\n\n/** Returned by pull(), passed to update(). Immutable. */\nexport interface PullResult {\n readonly arm: Arm;\n readonly eventId: string;\n readonly banditId: number;\n readonly banditName: string;\n readonly scores: Readonly<Record<number, number>>;\n /** Convenience reach-through to arm.modelName. */\n readonly model: string;\n /** Convenience reach-through to arm.systemPrompt. */\n readonly prompt: string;\n /** @internal perf timestamp */\n readonly _pullTime: number;\n}\n\n/** Create a frozen Arm from raw wire data. */\nexport function createArm(data: {\n arm_id: number;\n model_name: string;\n model_provider: string;\n system_prompt: string;\n is_prompt_templated?: boolean;\n}): Arm {\n const arm: Arm = {\n armId: data.arm_id,\n modelName: data.model_name,\n modelProvider: data.model_provider,\n systemPrompt: data.system_prompt,\n isPromptTemplated: data.is_prompt_templated ?? false,\n get model() {\n return this.modelName;\n },\n get prompt() {\n return this.systemPrompt;\n },\n };\n return Object.freeze(arm);\n}\n\n/** Create a frozen PullResult. */\nexport function createPullResult(data: {\n arm: Arm;\n eventId: string;\n banditId: number;\n banditName: string;\n scores: Record<number, number>;\n pullTime: number;\n}): PullResult {\n const result: PullResult = {\n arm: data.arm,\n eventId: data.eventId,\n banditId: data.banditId,\n banditName: data.banditName,\n scores: Object.freeze({ ...data.scores }),\n get model() {\n return this.arm.modelName;\n },\n get prompt() {\n return this.arm.systemPrompt;\n },\n _pullTime: data.pullTime,\n };\n return Object.freeze(result);\n}\n\n/** Raw arm data from sync response (snake_case wire format). */\nexport interface ArmWire {\n arm_id: number;\n model_name: string;\n model_provider: string;\n system_prompt: string;\n is_prompt_templated: boolean;\n is_active: boolean;\n avg_latency_last_n: number | null;\n}\n\n/** Internal mutable cache for a bandit's state. */\nexport interface BanditCache {\n banditId: number;\n name: string;\n arms: Arm[]; // active only\n armWire: ArmWire[]; // all arms (for engine JSON)\n optimizationMode: string;\n avgLatencyLastN: number | null;\n budget: number | null;\n totalCost: number | null;\n}\n","/**\n * Config loader — reads ~/.bandito/config.toml and env vars.\n *\n * Resolution order: constructor args → env vars → TOML → defaults.\n * Same file as the Python SDK uses.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { parse as parseToml } from \"smol-toml\";\n\nexport const DEFAULT_BASE_URL = \"https://bandito-api.onrender.com\";\nconst CONFIG_DIR = path.join(os.homedir(), \".bandito\");\nconst CONFIG_FILE = path.join(CONFIG_DIR, \"config.toml\");\n\nexport interface BanditoConfig {\n apiKey: string | null;\n baseUrl: string;\n dataStorage: string; // \"local\" or \"cloud\"\n}\n\n/**\n * Load config from TOML file + env var overrides.\n */\nexport function loadConfig(): BanditoConfig {\n const config: BanditoConfig = {\n apiKey: null,\n baseUrl: DEFAULT_BASE_URL,\n dataStorage: \"local\",\n };\n\n // TOML file first\n if (fs.existsSync(CONFIG_FILE)) {\n try {\n const content = fs.readFileSync(CONFIG_FILE, \"utf-8\");\n const data = parseToml(content);\n if (data.api_key) config.apiKey = data.api_key;\n if (data.base_url) config.baseUrl = data.base_url;\n if (data.data_storage) config.dataStorage = data.data_storage;\n } catch {\n // Failed to parse TOML — fall back to env vars\n }\n }\n\n // Env vars override\n const envKey = process.env.BANDITO_API_KEY;\n if (envKey) config.apiKey = envKey;\n\n const envUrl = process.env.BANDITO_BASE_URL;\n if (envUrl) config.baseUrl = envUrl;\n\n const envStorage = process.env.BANDITO_DATA_STORAGE;\n if (envStorage) config.dataStorage = envStorage;\n\n return config;\n}\n","/**\n * HTTP transport — fetch-based client for cloud API.\n *\n * Retry config: 3 attempts, exponential backoff (0.5s, 1s, 2s),\n * retries only 5xx and network errors. Never retries 4xx.\n */\n\nconst MAX_RETRIES = 3;\nconst RETRY_BACKOFF_BASE = 500; // ms — 500, 1000, 2000\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isRetryable(status: number): boolean {\n return status >= 500;\n}\n\nexport class BanditoHTTP {\n private baseUrl: string;\n private apiKey: string;\n private timeout: number;\n\n constructor(baseUrl: string, apiKey: string, timeout: number = 10_000) {\n this.baseUrl = `${baseUrl.replace(/\\/$/, \"\")}/api/v1`;\n this.apiKey = apiKey;\n this.timeout = timeout;\n }\n\n private async request(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<Record<string, unknown>> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const resp = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: {\n \"X-API-Key\": this.apiKey,\n \"Content-Type\": \"application/json\",\n },\n body: body != null ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n\n if (!resp.ok) {\n const text = await resp.text().catch(() => \"\");\n if (!isRetryable(resp.status) || attempt === MAX_RETRIES - 1) {\n throw new Error(\n `HTTP ${resp.status} on ${method} ${path}: ${text}`,\n );\n }\n // Retryable server error — fall through to retry\n lastError = new Error(\n `HTTP ${resp.status} on ${method} ${path}: ${text}`,\n );\n } else {\n return (await resp.json()) as Record<string, unknown>;\n }\n } catch (err) {\n clearTimeout(timer);\n lastError = err as Error;\n\n // AbortError = timeout, TypeError = network error (in fetch)\n const isNetworkOrTimeout =\n (err as Error).name === \"AbortError\" ||\n (err as Error).name === \"TypeError\";\n if (!isNetworkOrTimeout && attempt < MAX_RETRIES - 1) {\n // Non-retryable (4xx already handled above)\n throw err;\n }\n if (attempt === MAX_RETRIES - 1) {\n throw err;\n }\n }\n\n // Exponential backoff\n const delay = RETRY_BACKOFF_BASE * 2 ** attempt;\n await sleep(delay);\n }\n\n throw lastError!;\n }\n\n /** POST /sync/connect — SDK bootstrap. */\n async connect(): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/sync/connect\");\n }\n\n /** POST /sync/heartbeat — periodic state refresh. */\n async heartbeat(): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/sync/heartbeat\", {});\n }\n\n /** POST /events — batch event ingestion. */\n async ingestEvents(\n events: Record<string, unknown>[],\n ): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/events\", { events });\n }\n\n /** PATCH /events/{uuid}/grade — submit human grade. */\n async submitGrade(\n eventUuid: string,\n grade: number,\n ): Promise<Record<string, unknown>> {\n return this.request(\"PATCH\", `/events/${eventUuid}/grade`, {\n grade,\n is_graded: true,\n });\n }\n}\n","/**\n * SQLite WAL durability layer — crash-safe event storage.\n *\n * Events are written here immediately after update(). Background flush\n * sends them to cloud. If the process crashes, pending events survive\n * and are retried on next connect().\n */\n\nimport Database from \"better-sqlite3\";\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS events (\n local_event_uuid TEXT PRIMARY KEY,\n bandit_id INTEGER NOT NULL,\n arm_id INTEGER NOT NULL,\n payload TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n created_at REAL NOT NULL,\n human_reward REAL,\n graded_at REAL\n);\nCREATE INDEX IF NOT EXISTS idx_events_status ON events(status);\n`;\n\nconst MIGRATION_GRADING = [\n \"ALTER TABLE events ADD COLUMN human_reward REAL\",\n \"ALTER TABLE events ADD COLUMN graded_at REAL\",\n];\n\nexport interface EventPayload {\n local_event_uuid: string;\n bandit_id: number;\n arm_id: number;\n [key: string]: unknown;\n}\n\nexport class EventStore {\n private db: Database.Database;\n private pushStmt: Database.Statement;\n private pendingStmt: Database.Statement;\n\n constructor(dbPath: string = \":memory:\") {\n this.db = new Database(dbPath);\n this.db.pragma(\"journal_mode = WAL\");\n this.db.pragma(\"busy_timeout = 5000\");\n this.db.pragma(\"synchronous = NORMAL\");\n this.db.exec(SCHEMA);\n this.migrate();\n\n // Pre-compile frequently-used statements\n this.pushStmt = this.db.prepare(\n `INSERT OR IGNORE INTO events\n (local_event_uuid, bandit_id, arm_id, payload, status, created_at)\n VALUES (?, ?, ?, ?, 'pending', ?)`,\n );\n this.pendingStmt = this.db.prepare(\n `SELECT payload FROM events WHERE status = 'pending'\n ORDER BY created_at ASC LIMIT ?`,\n );\n }\n\n /** Insert a pending event. */\n push(event: EventPayload): void {\n this.pushStmt.run(\n event.local_event_uuid,\n event.bandit_id,\n event.arm_id,\n JSON.stringify(event),\n Date.now() / 1000,\n );\n }\n\n /** Return up to `limit` pending events (oldest first). */\n pending(limit: number = 50): EventPayload[] {\n const rows = this.pendingStmt.all(limit) as { payload: string }[];\n return rows.map((row) => JSON.parse(row.payload));\n }\n\n /** Mark events as successfully flushed to cloud. */\n markFlushed(uuids: string[]): void {\n if (uuids.length === 0) return;\n const placeholders = uuids.map(() => \"?\").join(\",\");\n this.db\n .prepare(\n `UPDATE events SET status = 'flushed'\n WHERE local_event_uuid IN (${placeholders})`,\n )\n .run(...uuids);\n }\n\n /** Record a human grade locally. */\n markGraded(uuid: string, reward: number): void {\n this.db\n .prepare(\n `UPDATE events SET human_reward = ?, graded_at = ?\n WHERE local_event_uuid = ?`,\n )\n .run(reward, Date.now() / 1000, uuid);\n }\n\n /** Close the database connection. */\n close(): void {\n this.db.close();\n }\n\n private migrate(): void {\n for (const stmt of MIGRATION_GRADING) {\n try {\n this.db.exec(stmt);\n } catch {\n // Column already exists\n }\n }\n }\n}\n","/**\n * Payload utilities for cloud event ingestion.\n */\n\nconst TEXT_FIELDS = [\"query_text\", \"response\"] as const;\nconst METADATA_FIELDS = [\"model_name\", \"model_provider\"] as const;\n\n/**\n * Return shallow copies of events ready for cloud ingest.\n *\n * Always strips model_name/model_provider (only needed in local SQLite for TUI).\n * Strips query_text/response when includeText is false (dataStorage=\"local\").\n */\nexport function prepareCloudPayload(\n events: Record<string, unknown>[],\n includeText: boolean,\n): Record<string, unknown>[] {\n return events.map((event) => {\n const copy = { ...event };\n for (const field of METADATA_FIELDS) {\n delete copy[field];\n }\n if (!includeText) {\n for (const field of TEXT_FIELDS) {\n delete copy[field];\n }\n }\n return copy;\n });\n}\n","/**\n * Bandito SDK — contextual bandit optimization for LLM selection.\n *\n * Recommended (explicit client):\n * import { BanditoClient } from 'bandito';\n *\n * const client = new BanditoClient({ apiKey: 'bnd_...' });\n * await client.connect();\n * const result = client.pull('my-chatbot', { query: userMessage });\n * // ... call LLM with result.model, result.prompt ...\n * client.update(result, { response: response.text });\n * await client.close();\n *\n * Module-level singleton (convenience):\n * import { connect, pull, update, close } from 'bandito';\n *\n * await connect({ apiKey: 'bnd_...' });\n * const result = pull('my-chatbot', { query: userMessage });\n * update(result, { response: response.text });\n * await close();\n */\n\nexport { BanditoClient, type ClientOptions, type PullOptions, type UpdateOptions } from \"./client.js\";\nexport { type Arm, type PullResult } from \"./models.js\";\n\nimport { BanditoClient, type ClientOptions, type PullOptions, type UpdateOptions } from \"./client.js\";\nimport type { PullResult } from \"./models.js\";\n\nlet _client: BanditoClient | null = null;\n\nfunction getClient(): BanditoClient {\n if (!_client) {\n throw new Error(\"Not connected — call connect() first\");\n }\n return _client;\n}\n\n/** Connect to the Bandito cloud and hydrate local state. */\nexport async function connect(options: ClientOptions = {}): Promise<void> {\n if (_client) {\n await _client.close();\n }\n _client = new BanditoClient(options);\n await _client.connect();\n}\n\n/** Local Thompson Sampling decision. <1ms, no network. */\nexport function pull(banditName: string, options?: PullOptions): PullResult {\n return getClient().pull(banditName, options);\n}\n\n/** Record an LLM call outcome (writes to SQLite, fire-and-forget flush). */\nexport function update(pullResult: PullResult, options?: UpdateOptions): void {\n getClient().update(pullResult, options);\n}\n\n/** Send a human grade for an existing event. */\nexport async function grade(eventId: string, gradeValue: number): Promise<void> {\n await getClient().grade(eventId, gradeValue);\n}\n\n/** Explicit state refresh from cloud. */\nexport async function sync(): Promise<void> {\n await getClient().sync();\n}\n\n/** Shut down: flush events, close connections. */\nexport async function close(): Promise<void> {\n if (_client) {\n await _client.close();\n _client = null;\n }\n}\n"],"mappings":"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","names":["fs","path","os","path","grade","grade"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bandito-ai/sdk",
|
|
3
|
+
"version": "0.1.7",
|
|
4
|
+
"description": "Contextual bandit optimizer for LLM model and prompt selection",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"wasm"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"better-sqlite3": "^11.0.0",
|
|
21
|
+
"smol-toml": "^1.3.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/better-sqlite3": "^7.6.0",
|
|
25
|
+
"msw": "^2.0.0",
|
|
26
|
+
"tsup": "^8.0.0",
|
|
27
|
+
"typescript": "^5.7.0",
|
|
28
|
+
"vitest": "^3.0.0"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18.0.0"
|
|
32
|
+
},
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"keywords": [
|
|
35
|
+
"llm",
|
|
36
|
+
"bandit",
|
|
37
|
+
"optimization",
|
|
38
|
+
"ai",
|
|
39
|
+
"prompt",
|
|
40
|
+
"model-selection",
|
|
41
|
+
"thompson-sampling"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build:wasm": "cd ../../engine && wasm-pack build --target nodejs --out-dir pkg --features wasm",
|
|
45
|
+
"copy:wasm": "mkdir -p wasm && cp ../../engine/pkg/bandito_engine* wasm/",
|
|
46
|
+
"prebuild": "npm run copy:wasm",
|
|
47
|
+
"build": "tsup",
|
|
48
|
+
"pretest": "npm run copy:wasm",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"test:watch": "vitest",
|
|
51
|
+
"lint": "tsc --noEmit"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The engine struct exposed to WASM. Wraps BanditEngineCore.
|
|
6
|
+
*/
|
|
7
|
+
export class BanditEngine {
|
|
8
|
+
free(): void;
|
|
9
|
+
[Symbol.dispose](): void;
|
|
10
|
+
/**
|
|
11
|
+
* Get the arm metadata as JSON array.
|
|
12
|
+
*/
|
|
13
|
+
getArmsJson(): string;
|
|
14
|
+
/**
|
|
15
|
+
* Construct from sync response JSON for one bandit.
|
|
16
|
+
*/
|
|
17
|
+
constructor(bandit_json: string);
|
|
18
|
+
/**
|
|
19
|
+
* Construct with an explicit RNG seed (for testing).
|
|
20
|
+
*/
|
|
21
|
+
static newWithSeed(bandit_json: string, seed?: bigint | null): BanditEngine;
|
|
22
|
+
/**
|
|
23
|
+
* Pure math pull — returns JSON { arm_index, arm_id, scores }.
|
|
24
|
+
*/
|
|
25
|
+
pull(query_length?: number | null, exclude_ids?: Int32Array | null): string;
|
|
26
|
+
/**
|
|
27
|
+
* Update state from new sync response.
|
|
28
|
+
*/
|
|
29
|
+
updateFromSync(bandit_json: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Get the bandit ID.
|
|
32
|
+
*/
|
|
33
|
+
readonly banditId: bigint;
|
|
34
|
+
/**
|
|
35
|
+
* Get the bandit name.
|
|
36
|
+
*/
|
|
37
|
+
readonly banditName: string;
|
|
38
|
+
/**
|
|
39
|
+
* Get dimensions.
|
|
40
|
+
*/
|
|
41
|
+
readonly dimensions: number;
|
|
42
|
+
/**
|
|
43
|
+
* Get number of arms (all, including inactive).
|
|
44
|
+
*/
|
|
45
|
+
readonly numArms: number;
|
|
46
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/* @ts-self-types="./bandito_engine.d.ts" */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The engine struct exposed to WASM. Wraps BanditEngineCore.
|
|
5
|
+
*/
|
|
6
|
+
class BanditEngine {
|
|
7
|
+
static __wrap(ptr) {
|
|
8
|
+
ptr = ptr >>> 0;
|
|
9
|
+
const obj = Object.create(BanditEngine.prototype);
|
|
10
|
+
obj.__wbg_ptr = ptr;
|
|
11
|
+
BanditEngineFinalization.register(obj, obj.__wbg_ptr, obj);
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
__destroy_into_raw() {
|
|
15
|
+
const ptr = this.__wbg_ptr;
|
|
16
|
+
this.__wbg_ptr = 0;
|
|
17
|
+
BanditEngineFinalization.unregister(this);
|
|
18
|
+
return ptr;
|
|
19
|
+
}
|
|
20
|
+
free() {
|
|
21
|
+
const ptr = this.__destroy_into_raw();
|
|
22
|
+
wasm.__wbg_banditengine_free(ptr, 0);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get the bandit ID.
|
|
26
|
+
* @returns {bigint}
|
|
27
|
+
*/
|
|
28
|
+
get banditId() {
|
|
29
|
+
const ret = wasm.banditengine_banditId(this.__wbg_ptr);
|
|
30
|
+
return ret;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get the bandit name.
|
|
34
|
+
* @returns {string}
|
|
35
|
+
*/
|
|
36
|
+
get banditName() {
|
|
37
|
+
let deferred1_0;
|
|
38
|
+
let deferred1_1;
|
|
39
|
+
try {
|
|
40
|
+
const ret = wasm.banditengine_banditName(this.__wbg_ptr);
|
|
41
|
+
deferred1_0 = ret[0];
|
|
42
|
+
deferred1_1 = ret[1];
|
|
43
|
+
return getStringFromWasm0(ret[0], ret[1]);
|
|
44
|
+
} finally {
|
|
45
|
+
wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get dimensions.
|
|
50
|
+
* @returns {number}
|
|
51
|
+
*/
|
|
52
|
+
get dimensions() {
|
|
53
|
+
const ret = wasm.banditengine_dimensions(this.__wbg_ptr);
|
|
54
|
+
return ret >>> 0;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get the arm metadata as JSON array.
|
|
58
|
+
* @returns {string}
|
|
59
|
+
*/
|
|
60
|
+
getArmsJson() {
|
|
61
|
+
let deferred1_0;
|
|
62
|
+
let deferred1_1;
|
|
63
|
+
try {
|
|
64
|
+
const ret = wasm.banditengine_getArmsJson(this.__wbg_ptr);
|
|
65
|
+
deferred1_0 = ret[0];
|
|
66
|
+
deferred1_1 = ret[1];
|
|
67
|
+
return getStringFromWasm0(ret[0], ret[1]);
|
|
68
|
+
} finally {
|
|
69
|
+
wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Construct from sync response JSON for one bandit.
|
|
74
|
+
* @param {string} bandit_json
|
|
75
|
+
*/
|
|
76
|
+
constructor(bandit_json) {
|
|
77
|
+
const ptr0 = passStringToWasm0(bandit_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
78
|
+
const len0 = WASM_VECTOR_LEN;
|
|
79
|
+
const ret = wasm.banditengine_new(ptr0, len0);
|
|
80
|
+
if (ret[2]) {
|
|
81
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
82
|
+
}
|
|
83
|
+
this.__wbg_ptr = ret[0] >>> 0;
|
|
84
|
+
BanditEngineFinalization.register(this, this.__wbg_ptr, this);
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Construct with an explicit RNG seed (for testing).
|
|
89
|
+
* @param {string} bandit_json
|
|
90
|
+
* @param {bigint | null} [seed]
|
|
91
|
+
* @returns {BanditEngine}
|
|
92
|
+
*/
|
|
93
|
+
static newWithSeed(bandit_json, seed) {
|
|
94
|
+
const ptr0 = passStringToWasm0(bandit_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
95
|
+
const len0 = WASM_VECTOR_LEN;
|
|
96
|
+
const ret = wasm.banditengine_newWithSeed(ptr0, len0, !isLikeNone(seed), isLikeNone(seed) ? BigInt(0) : seed);
|
|
97
|
+
if (ret[2]) {
|
|
98
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
99
|
+
}
|
|
100
|
+
return BanditEngine.__wrap(ret[0]);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get number of arms (all, including inactive).
|
|
104
|
+
* @returns {number}
|
|
105
|
+
*/
|
|
106
|
+
get numArms() {
|
|
107
|
+
const ret = wasm.banditengine_numArms(this.__wbg_ptr);
|
|
108
|
+
return ret >>> 0;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Pure math pull — returns JSON { arm_index, arm_id, scores }.
|
|
112
|
+
* @param {number | null} [query_length]
|
|
113
|
+
* @param {Int32Array | null} [exclude_ids]
|
|
114
|
+
* @returns {string}
|
|
115
|
+
*/
|
|
116
|
+
pull(query_length, exclude_ids) {
|
|
117
|
+
let deferred3_0;
|
|
118
|
+
let deferred3_1;
|
|
119
|
+
try {
|
|
120
|
+
var ptr0 = isLikeNone(exclude_ids) ? 0 : passArray32ToWasm0(exclude_ids, wasm.__wbindgen_malloc);
|
|
121
|
+
var len0 = WASM_VECTOR_LEN;
|
|
122
|
+
const ret = wasm.banditengine_pull(this.__wbg_ptr, isLikeNone(query_length) ? 0x100000001 : (query_length) >>> 0, ptr0, len0);
|
|
123
|
+
var ptr2 = ret[0];
|
|
124
|
+
var len2 = ret[1];
|
|
125
|
+
if (ret[3]) {
|
|
126
|
+
ptr2 = 0; len2 = 0;
|
|
127
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
128
|
+
}
|
|
129
|
+
deferred3_0 = ptr2;
|
|
130
|
+
deferred3_1 = len2;
|
|
131
|
+
return getStringFromWasm0(ptr2, len2);
|
|
132
|
+
} finally {
|
|
133
|
+
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Update state from new sync response.
|
|
138
|
+
* @param {string} bandit_json
|
|
139
|
+
*/
|
|
140
|
+
updateFromSync(bandit_json) {
|
|
141
|
+
const ptr0 = passStringToWasm0(bandit_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
142
|
+
const len0 = WASM_VECTOR_LEN;
|
|
143
|
+
const ret = wasm.banditengine_updateFromSync(this.__wbg_ptr, ptr0, len0);
|
|
144
|
+
if (ret[1]) {
|
|
145
|
+
throw takeFromExternrefTable0(ret[0]);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (Symbol.dispose) BanditEngine.prototype[Symbol.dispose] = BanditEngine.prototype.free;
|
|
150
|
+
exports.BanditEngine = BanditEngine;
|
|
151
|
+
|
|
152
|
+
function __wbg_get_imports() {
|
|
153
|
+
const import0 = {
|
|
154
|
+
__proto__: null,
|
|
155
|
+
__wbg___wbindgen_throw_39bc967c0e5a9b58: function(arg0, arg1) {
|
|
156
|
+
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
157
|
+
},
|
|
158
|
+
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
159
|
+
// Cast intrinsic for `Ref(String) -> Externref`.
|
|
160
|
+
const ret = getStringFromWasm0(arg0, arg1);
|
|
161
|
+
return ret;
|
|
162
|
+
},
|
|
163
|
+
__wbindgen_init_externref_table: function() {
|
|
164
|
+
const table = wasm.__wbindgen_externrefs;
|
|
165
|
+
const offset = table.grow(4);
|
|
166
|
+
table.set(0, undefined);
|
|
167
|
+
table.set(offset + 0, undefined);
|
|
168
|
+
table.set(offset + 1, null);
|
|
169
|
+
table.set(offset + 2, true);
|
|
170
|
+
table.set(offset + 3, false);
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
return {
|
|
174
|
+
__proto__: null,
|
|
175
|
+
"./bandito_engine_bg.js": import0,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const BanditEngineFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
180
|
+
? { register: () => {}, unregister: () => {} }
|
|
181
|
+
: new FinalizationRegistry(ptr => wasm.__wbg_banditengine_free(ptr >>> 0, 1));
|
|
182
|
+
|
|
183
|
+
function getStringFromWasm0(ptr, len) {
|
|
184
|
+
ptr = ptr >>> 0;
|
|
185
|
+
return decodeText(ptr, len);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
let cachedUint32ArrayMemory0 = null;
|
|
189
|
+
function getUint32ArrayMemory0() {
|
|
190
|
+
if (cachedUint32ArrayMemory0 === null || cachedUint32ArrayMemory0.byteLength === 0) {
|
|
191
|
+
cachedUint32ArrayMemory0 = new Uint32Array(wasm.memory.buffer);
|
|
192
|
+
}
|
|
193
|
+
return cachedUint32ArrayMemory0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
let cachedUint8ArrayMemory0 = null;
|
|
197
|
+
function getUint8ArrayMemory0() {
|
|
198
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
199
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
200
|
+
}
|
|
201
|
+
return cachedUint8ArrayMemory0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function isLikeNone(x) {
|
|
205
|
+
return x === undefined || x === null;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function passArray32ToWasm0(arg, malloc) {
|
|
209
|
+
const ptr = malloc(arg.length * 4, 4) >>> 0;
|
|
210
|
+
getUint32ArrayMemory0().set(arg, ptr / 4);
|
|
211
|
+
WASM_VECTOR_LEN = arg.length;
|
|
212
|
+
return ptr;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
216
|
+
if (realloc === undefined) {
|
|
217
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
218
|
+
const ptr = malloc(buf.length, 1) >>> 0;
|
|
219
|
+
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
|
220
|
+
WASM_VECTOR_LEN = buf.length;
|
|
221
|
+
return ptr;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
let len = arg.length;
|
|
225
|
+
let ptr = malloc(len, 1) >>> 0;
|
|
226
|
+
|
|
227
|
+
const mem = getUint8ArrayMemory0();
|
|
228
|
+
|
|
229
|
+
let offset = 0;
|
|
230
|
+
|
|
231
|
+
for (; offset < len; offset++) {
|
|
232
|
+
const code = arg.charCodeAt(offset);
|
|
233
|
+
if (code > 0x7F) break;
|
|
234
|
+
mem[ptr + offset] = code;
|
|
235
|
+
}
|
|
236
|
+
if (offset !== len) {
|
|
237
|
+
if (offset !== 0) {
|
|
238
|
+
arg = arg.slice(offset);
|
|
239
|
+
}
|
|
240
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
241
|
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
242
|
+
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
243
|
+
|
|
244
|
+
offset += ret.written;
|
|
245
|
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
WASM_VECTOR_LEN = offset;
|
|
249
|
+
return ptr;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function takeFromExternrefTable0(idx) {
|
|
253
|
+
const value = wasm.__wbindgen_externrefs.get(idx);
|
|
254
|
+
wasm.__externref_table_dealloc(idx);
|
|
255
|
+
return value;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
259
|
+
cachedTextDecoder.decode();
|
|
260
|
+
function decodeText(ptr, len) {
|
|
261
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const cachedTextEncoder = new TextEncoder();
|
|
265
|
+
|
|
266
|
+
if (!('encodeInto' in cachedTextEncoder)) {
|
|
267
|
+
cachedTextEncoder.encodeInto = function (arg, view) {
|
|
268
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
269
|
+
view.set(buf);
|
|
270
|
+
return {
|
|
271
|
+
read: arg.length,
|
|
272
|
+
written: buf.length
|
|
273
|
+
};
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
let WASM_VECTOR_LEN = 0;
|
|
278
|
+
|
|
279
|
+
const wasmPath = `${__dirname}/bandito_engine_bg.wasm`;
|
|
280
|
+
const wasmBytes = require('fs').readFileSync(wasmPath);
|
|
281
|
+
const wasmModule = new WebAssembly.Module(wasmBytes);
|
|
282
|
+
let wasm = new WebAssembly.Instance(wasmModule, __wbg_get_imports()).exports;
|
|
283
|
+
wasm.__wbindgen_start();
|
|
Binary file
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const __wbg_banditengine_free: (a: number, b: number) => void;
|
|
5
|
+
export const banditengine_banditId: (a: number) => bigint;
|
|
6
|
+
export const banditengine_banditName: (a: number) => [number, number];
|
|
7
|
+
export const banditengine_dimensions: (a: number) => number;
|
|
8
|
+
export const banditengine_getArmsJson: (a: number) => [number, number];
|
|
9
|
+
export const banditengine_new: (a: number, b: number) => [number, number, number];
|
|
10
|
+
export const banditengine_newWithSeed: (a: number, b: number, c: number, d: bigint) => [number, number, number];
|
|
11
|
+
export const banditengine_numArms: (a: number) => number;
|
|
12
|
+
export const banditengine_pull: (a: number, b: number, c: number, d: number) => [number, number, number, number];
|
|
13
|
+
export const banditengine_updateFromSync: (a: number, b: number, c: number) => [number, number];
|
|
14
|
+
export const __wbindgen_externrefs: WebAssembly.Table;
|
|
15
|
+
export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
|
16
|
+
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
17
|
+
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
18
|
+
export const __externref_table_dealloc: (a: number) => void;
|
|
19
|
+
export const __wbindgen_start: () => void;
|