@framers/sql-storage-adapter 0.2.0 → 0.3.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.
@@ -0,0 +1,367 @@
1
+ /**
2
+ * @fileoverview IndexedDB Storage Adapter for AgentOS
3
+ * @description Browser-native SQL storage using IndexedDB with sql.js for full client-side operation.
4
+ * Supports transactions, persistence to IndexedDB, and offline-first workflows.
5
+ *
6
+ * **Use cases:**
7
+ * - Fully client-side AgentOS (no backend needed)
8
+ * - Progressive Web Apps (PWAs)
9
+ * - Offline-capable agents
10
+ * - Privacy-first applications (data never leaves browser)
11
+ *
12
+ * **Architecture:**
13
+ * - Uses sql.js (SQLite compiled to WebAssembly) for SQL execution
14
+ * - Persists database to IndexedDB for durability across sessions
15
+ * - Auto-saves after each transaction
16
+ * - Supports import/export for data portability
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * import { IndexedDbAdapter } from '../adapters/indexedDbAdapter';
21
+ *
22
+ * const adapter = new IndexedDbAdapter({
23
+ * dbName: 'agentos-client-db',
24
+ * autoSave: true,
25
+ * saveIntervalMs: 5000,
26
+ * });
27
+ *
28
+ * await adapter.open();
29
+ * await adapter.run('CREATE TABLE sessions (id TEXT PRIMARY KEY, data TEXT)');
30
+ * await adapter.run('INSERT INTO sessions VALUES (?, ?)', ['session-1', '{"events": []}']);
31
+ *
32
+ * const session = await adapter.get('SELECT * FROM sessions WHERE id = ?', ['session-1']);
33
+ * console.log(session);
34
+ * ```
35
+ */
36
+ import initSqlJs from 'sql.js';
37
+ import { normaliseParameters } from '../shared/parameterUtils';
38
+ const DB_VERSION = 1;
39
+ /**
40
+ * Storage adapter using IndexedDB + sql.js for client-side SQL persistence.
41
+ *
42
+ * **Capabilities:**
43
+ * - ✅ Transactions
44
+ * - ✅ Persistence (IndexedDB)
45
+ * - ✅ Full SQL support (via sql.js)
46
+ * - ✅ Export/import
47
+ * - ❌ Concurrent writes (single-threaded)
48
+ * - ❌ Server-side (browser only)
49
+ *
50
+ * **Performance:**
51
+ * - Fast reads (in-memory SQL)
52
+ * - Moderate writes (IndexedDB persistence)
53
+ * - Auto-save batching reduces IDB overhead
54
+ *
55
+ * @example Client-side AgentOS
56
+ * ```typescript
57
+ * const adapter = new IndexedDbAdapter({ dbName: 'my-app-db' });
58
+ * const agentos = new AgentOS();
59
+ * await agentos.initialize({
60
+ * storageAdapter: adapter,
61
+ * // ... other config
62
+ * });
63
+ * ```
64
+ */
65
+ export class IndexedDbAdapter {
66
+ constructor(options = {}) {
67
+ this.kind = 'indexeddb';
68
+ this.capabilities = new Set(['transactions', 'persistence']);
69
+ this.SQL = null;
70
+ this.db = null;
71
+ this.idb = null;
72
+ this.saveTimer = null;
73
+ this.dirty = false;
74
+ this.dbName = options.dbName || 'agentos-db';
75
+ this.storeName = options.storeName || 'sqliteDb';
76
+ this.autoSave = options.autoSave ?? true;
77
+ this.saveIntervalMs = options.saveIntervalMs || 5000;
78
+ this.sqlJsConfig = options.sqlJsConfig || {};
79
+ }
80
+ /**
81
+ * Opens IndexedDB and initializes sql.js database.
82
+ * Loads existing database from IndexedDB if present.
83
+ */
84
+ async open(_options) {
85
+ if (this.db) {
86
+ return; // Already open
87
+ }
88
+ // Initialize sql.js
89
+ this.SQL = await initSqlJs(this.sqlJsConfig);
90
+ // Open IndexedDB
91
+ this.idb = await this.openIndexedDb();
92
+ // Load existing database from IndexedDB or create new
93
+ const existingData = await this.loadFromIndexedDb();
94
+ if (existingData) {
95
+ this.db = new this.SQL.Database(existingData);
96
+ }
97
+ else {
98
+ this.db = new this.SQL.Database();
99
+ }
100
+ // Start auto-save interval
101
+ if (this.autoSave) {
102
+ this.startAutoSave();
103
+ }
104
+ }
105
+ /**
106
+ * Executes a SQL statement that doesn't return rows (INSERT, UPDATE, DELETE, CREATE, etc.).
107
+ * @param statement SQL statement with ? or :name placeholders
108
+ * @param parameters Positional array or named object
109
+ * @returns Result with changes count and last insert row ID
110
+ */
111
+ async run(statement, parameters) {
112
+ this.ensureOpen();
113
+ const stmt = this.db.prepare(statement);
114
+ try {
115
+ const { named, positional } = normaliseParameters(parameters);
116
+ if (named) {
117
+ stmt.bind(named);
118
+ }
119
+ else if (positional) {
120
+ stmt.bind(positional);
121
+ }
122
+ stmt.step();
123
+ const rowIdResult = this.db.exec('SELECT last_insert_rowid() AS id');
124
+ const rawRowId = rowIdResult[0]?.values?.[0]?.[0];
125
+ const lastInsertRowid = this.normaliseRowId(rawRowId);
126
+ this.dirty = true;
127
+ await this.persistIfNeeded();
128
+ return {
129
+ changes: this.db.getRowsModified(),
130
+ lastInsertRowid,
131
+ };
132
+ }
133
+ finally {
134
+ stmt.free();
135
+ }
136
+ }
137
+ /**
138
+ * Executes a SQL query and returns the first row.
139
+ * @param statement SELECT statement
140
+ * @param parameters Query parameters
141
+ * @returns First row as object or null if no results
142
+ */
143
+ async get(statement, parameters) {
144
+ const rows = await this.all(statement, parameters);
145
+ return rows.length > 0 ? rows[0] : null;
146
+ }
147
+ /**
148
+ * Executes a SQL query and returns all matching rows.
149
+ * @param statement SELECT statement
150
+ * @param parameters Query parameters
151
+ * @returns Array of result rows as objects
152
+ */
153
+ async all(statement, parameters) {
154
+ this.ensureOpen();
155
+ const stmt = this.db.prepare(statement);
156
+ try {
157
+ const { named, positional } = normaliseParameters(parameters);
158
+ if (named) {
159
+ stmt.bind(named);
160
+ }
161
+ else if (positional) {
162
+ stmt.bind(positional);
163
+ }
164
+ const results = [];
165
+ const columnNames = stmt.getColumnNames();
166
+ while (stmt.step()) {
167
+ const row = stmt.get();
168
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
169
+ const obj = {};
170
+ columnNames.forEach((col, idx) => {
171
+ obj[col] = row[idx];
172
+ });
173
+ results.push(obj);
174
+ }
175
+ return results;
176
+ }
177
+ finally {
178
+ stmt.free();
179
+ }
180
+ }
181
+ /**
182
+ * Executes a script containing multiple SQL statements.
183
+ */
184
+ async exec(script) {
185
+ this.ensureOpen();
186
+ this.db.exec(script);
187
+ this.dirty = true;
188
+ await this.persistIfNeeded();
189
+ }
190
+ /**
191
+ * Executes a callback within a database transaction.
192
+ */
193
+ async transaction(fn) {
194
+ this.ensureOpen();
195
+ await this.run('BEGIN TRANSACTION');
196
+ try {
197
+ const result = await fn(this);
198
+ await this.run('COMMIT');
199
+ this.dirty = true;
200
+ await this.persistIfNeeded();
201
+ return result;
202
+ }
203
+ catch (error) {
204
+ await this.run('ROLLBACK');
205
+ throw error;
206
+ }
207
+ }
208
+ /**
209
+ * Begins a transaction. sql.js executes all statements in implicit transactions,
210
+ * so this is a no-op for compatibility.
211
+ */
212
+ async beginTransaction() {
213
+ // sql.js uses auto-commit; explicit BEGIN is optional
214
+ await this.run('BEGIN');
215
+ }
216
+ /**
217
+ * Commits the current transaction.
218
+ */
219
+ async commit() {
220
+ await this.run('COMMIT');
221
+ this.dirty = true;
222
+ await this.persistIfNeeded();
223
+ }
224
+ /**
225
+ * Rolls back the current transaction.
226
+ */
227
+ async rollback() {
228
+ await this.run('ROLLBACK');
229
+ }
230
+ /**
231
+ * Closes the database and persists final state to IndexedDB.
232
+ */
233
+ async close() {
234
+ if (this.saveTimer) {
235
+ clearInterval(this.saveTimer);
236
+ this.saveTimer = null;
237
+ }
238
+ if (this.dirty) {
239
+ await this.saveToIndexedDb();
240
+ }
241
+ if (this.db) {
242
+ this.db.close();
243
+ this.db = null;
244
+ }
245
+ if (this.idb) {
246
+ this.idb.close();
247
+ this.idb = null;
248
+ }
249
+ }
250
+ /**
251
+ * Exports the database as a Uint8Array (SQLite file format).
252
+ * Can be downloaded or stored externally.
253
+ * @returns SQLite database file as binary
254
+ */
255
+ exportDatabase() {
256
+ this.ensureOpen();
257
+ return this.db.export();
258
+ }
259
+ /**
260
+ * Imports a database from a Uint8Array (SQLite file).
261
+ * Replaces the current database.
262
+ * @param data SQLite database file
263
+ */
264
+ async importDatabase(data) {
265
+ this.ensureOpen();
266
+ this.db.close();
267
+ this.db = new this.SQL.Database(data);
268
+ this.dirty = true;
269
+ await this.saveToIndexedDb();
270
+ }
271
+ /**
272
+ * Opens or creates the IndexedDB database.
273
+ */
274
+ openIndexedDb() {
275
+ return new Promise((resolve, reject) => {
276
+ const req = indexedDB.open(this.dbName, DB_VERSION);
277
+ req.onupgradeneeded = () => {
278
+ const db = req.result;
279
+ if (!db.objectStoreNames.contains(this.storeName)) {
280
+ db.createObjectStore(this.storeName);
281
+ }
282
+ };
283
+ req.onsuccess = () => resolve(req.result);
284
+ req.onerror = () => reject(req.error);
285
+ });
286
+ }
287
+ /**
288
+ * Loads the SQLite database from IndexedDB.
289
+ * @returns Binary database or null if not found
290
+ */
291
+ async loadFromIndexedDb() {
292
+ if (!this.idb)
293
+ return null;
294
+ return new Promise((resolve, reject) => {
295
+ const tx = this.idb.transaction(this.storeName, 'readonly');
296
+ const store = tx.objectStore(this.storeName);
297
+ const req = store.get('db');
298
+ req.onsuccess = () => resolve(req.result || null);
299
+ req.onerror = () => reject(req.error);
300
+ });
301
+ }
302
+ /**
303
+ * Saves the SQLite database to IndexedDB.
304
+ */
305
+ async saveToIndexedDb() {
306
+ if (!this.idb || !this.db)
307
+ return;
308
+ const data = this.db.export();
309
+ return new Promise((resolve, reject) => {
310
+ const tx = this.idb.transaction(this.storeName, 'readwrite');
311
+ const store = tx.objectStore(this.storeName);
312
+ const req = store.put(data, 'db');
313
+ req.onsuccess = () => {
314
+ this.dirty = false;
315
+ resolve();
316
+ };
317
+ req.onerror = () => reject(req.error);
318
+ });
319
+ }
320
+ /**
321
+ * Persists to IndexedDB if auto-save is enabled.
322
+ */
323
+ async persistIfNeeded() {
324
+ if (this.autoSave && !this.saveTimer) {
325
+ // Immediate save on first write, then batched
326
+ await this.saveToIndexedDb();
327
+ }
328
+ }
329
+ /**
330
+ * Starts auto-save interval.
331
+ */
332
+ startAutoSave() {
333
+ this.saveTimer = setInterval(async () => {
334
+ if (this.dirty) {
335
+ await this.saveToIndexedDb();
336
+ }
337
+ }, this.saveIntervalMs);
338
+ }
339
+ /**
340
+ * Ensures the database is open.
341
+ */
342
+ ensureOpen() {
343
+ if (!this.db) {
344
+ throw new Error('IndexedDbAdapter: Database not open. Call open() first.');
345
+ }
346
+ }
347
+ /**
348
+ * Normalizes last insert row ID to string or number.
349
+ */
350
+ normaliseRowId(value) {
351
+ if (typeof value === 'number' || typeof value === 'string') {
352
+ return value;
353
+ }
354
+ if (typeof value === 'bigint') {
355
+ return value.toString();
356
+ }
357
+ return null;
358
+ }
359
+ /**
360
+ * Prepares a SQL statement for execution.
361
+ */
362
+ prepareInternal(statement) {
363
+ this.ensureOpen();
364
+ return this.db.prepare(statement);
365
+ }
366
+ }
367
+ //# sourceMappingURL=indexedDbAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexedDbAdapter.js","sourceRoot":"","sources":["../../src/adapters/indexedDbAdapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,320 @@
1
+ /**
2
+ * @fileoverview AgentOS-First Storage Adapter
3
+ * @description Opinionated storage layer designed specifically for AgentOS with auto-schema,
4
+ * typed queries, and cross-platform persistence. This is the recommended way to use
5
+ * sql-storage-adapter with AgentOS.
6
+ *
7
+ * **Features:**
8
+ * - Auto-detects best adapter for platform (web, electron, capacitor, node, cloud)
9
+ * - Pre-configured schema for conversations, sessions, personas, telemetry
10
+ * - Typed query builders for common AgentOS operations
11
+ * - Optional cloud sync for hybrid local+remote architectures
12
+ * - Export/import for data portability
13
+ *
14
+ * @example Basic Usage
15
+ * ```typescript
16
+ * import { createAgentOSStorage } from '../agentos';
17
+ * import { AgentOS } from '@agentos/core';
18
+ *
19
+ * const storage = await createAgentOSStorage({
20
+ * platform: 'auto', // Detects: web, electron, capacitor, node, cloud
21
+ * persistence: true,
22
+ * });
23
+ *
24
+ * const agentos = new AgentOS();
25
+ * await agentos.initialize({
26
+ * storageAdapter: storage,
27
+ * // ... other config
28
+ * });
29
+ * ```
30
+ *
31
+ * @example Multi-Platform
32
+ * ```typescript
33
+ * // Web (browser): Uses IndexedDB
34
+ * const webStorage = await createAgentOSStorage({ platform: 'web' });
35
+ *
36
+ * // Desktop (Electron): Uses better-sqlite3
37
+ * const desktopStorage = await createAgentOSStorage({ platform: 'electron' });
38
+ *
39
+ * // Mobile (Capacitor): Uses native SQLite
40
+ * const mobileStorage = await createAgentOSStorage({ platform: 'capacitor' });
41
+ *
42
+ * // Cloud (Node): Uses PostgreSQL
43
+ * const cloudStorage = await createAgentOSStorage({
44
+ * platform: 'cloud',
45
+ * postgres: { connectionString: process.env.DATABASE_URL }
46
+ * });
47
+ * ```
48
+ *
49
+ * @example Hybrid Sync
50
+ * ```typescript
51
+ * const storage = await createAgentOSStorage({
52
+ * local: { adapter: 'indexeddb' },
53
+ * remote: { adapter: 'postgres', connectionString: CLOUD_URL },
54
+ * syncStrategy: 'optimistic', // Local-first, background sync
55
+ * syncIntervalMs: 30000,
56
+ * });
57
+ * ```
58
+ */
59
+ import type { StorageAdapter } from '../core/contracts';
60
+ import type { AdapterKind } from '../core/contracts/context';
61
+ /**
62
+ * Platform types for AgentOS deployment
63
+ */
64
+ export type AgentOSPlatform = 'web' | 'electron' | 'capacitor' | 'node' | 'cloud' | 'auto';
65
+ /**
66
+ * Sync strategy for hybrid local+remote storage
67
+ */
68
+ export type SyncStrategy = 'local-only' | 'remote-only' | 'optimistic' | 'pessimistic';
69
+ /**
70
+ * Configuration for AgentOS-optimized storage
71
+ */
72
+ export interface AgentOSStorageConfig {
73
+ /**
74
+ * Target platform. 'auto' detects runtime automatically.
75
+ * @default 'auto'
76
+ */
77
+ platform?: AgentOSPlatform;
78
+ /**
79
+ * Enable persistence (vs in-memory only).
80
+ * @default true
81
+ */
82
+ persistence?: boolean;
83
+ /**
84
+ * Database name (for IndexedDB, SQLite file, etc.)
85
+ * @default 'agentos-db'
86
+ */
87
+ dbName?: string;
88
+ /**
89
+ * File path for SQLite adapters
90
+ */
91
+ filePath?: string;
92
+ /**
93
+ * PostgreSQL connection config
94
+ */
95
+ postgres?: {
96
+ connectionString?: string;
97
+ };
98
+ /**
99
+ * Capacitor-specific options
100
+ */
101
+ capacitor?: {
102
+ database?: string;
103
+ encrypted?: boolean;
104
+ };
105
+ /**
106
+ * Features to enable (auto-creates tables)
107
+ * @default all enabled
108
+ */
109
+ features?: {
110
+ conversations?: boolean;
111
+ sessions?: boolean;
112
+ personas?: boolean;
113
+ telemetry?: boolean;
114
+ workflows?: boolean;
115
+ };
116
+ /**
117
+ * Optional cloud sync for hybrid architectures
118
+ */
119
+ cloudSync?: {
120
+ enabled?: boolean;
121
+ provider?: 'supabase' | 'postgres' | 'custom';
122
+ connectionString?: string;
123
+ syncStrategy?: SyncStrategy;
124
+ syncIntervalMs?: number;
125
+ };
126
+ /**
127
+ * Advanced: manual adapter priority override
128
+ */
129
+ adapterPriority?: AdapterKind[];
130
+ }
131
+ /**
132
+ * AgentOS-optimized storage adapter with auto-schema and typed queries.
133
+ *
134
+ * This class wraps a generic StorageAdapter and adds AgentOS-specific
135
+ * functionality like auto-schema creation, typed query builders, and
136
+ * optional cloud sync.
137
+ */
138
+ export declare class AgentOSStorageAdapter {
139
+ private adapter;
140
+ private config;
141
+ constructor(adapter: StorageAdapter, config: AgentOSStorageConfig);
142
+ /**
143
+ * Initializes the storage adapter and creates AgentOS schema.
144
+ */
145
+ initialize(): Promise<void>;
146
+ /**
147
+ * Gets the underlying storage adapter for custom queries.
148
+ */
149
+ getAdapter(): StorageAdapter;
150
+ /**
151
+ * Closes the storage adapter.
152
+ */
153
+ close(): Promise<void>;
154
+ /**
155
+ * Conversations API with typed query builders.
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * await storage.conversations.save('conv-1', 'user-1', 'v_researcher', [
160
+ * { type: 'user', content: 'Hello', timestamp: Date.now() },
161
+ * { type: 'assistant', content: 'Hi!', timestamp: Date.now() },
162
+ * ]);
163
+ *
164
+ * const conversation = await storage.conversations.get('conv-1');
165
+ * const allConversations = await storage.conversations.list('user-1', { limit: 50 });
166
+ * ```
167
+ */
168
+ get conversations(): {
169
+ /**
170
+ * Saves a conversation with its events.
171
+ * Creates the conversation if it doesn't exist, updates if it does.
172
+ */
173
+ save: (id: string, userId: string, personaId: string, events: any[]) => Promise<void>;
174
+ /**
175
+ * Gets a conversation by ID with all its events.
176
+ * Returns null if not found.
177
+ */
178
+ get: (id: string) => Promise<{
179
+ events: any[];
180
+ id: string;
181
+ user_id: string;
182
+ persona_id: string;
183
+ created_at: number;
184
+ updated_at: number;
185
+ metadata: string;
186
+ } | null>;
187
+ /**
188
+ * Lists conversations for a user, ordered by most recent first.
189
+ */
190
+ list: (userId: string, options?: {
191
+ limit?: number;
192
+ offset?: number;
193
+ }) => Promise<{
194
+ id: string;
195
+ user_id: string;
196
+ persona_id: string;
197
+ created_at: number;
198
+ updated_at: number;
199
+ metadata: string;
200
+ }[]>;
201
+ /**
202
+ * Deletes a conversation and all its events.
203
+ */
204
+ delete: (id: string) => Promise<void>;
205
+ };
206
+ /**
207
+ * Sessions API with typed query builders.
208
+ *
209
+ * @example
210
+ * ```typescript
211
+ * await storage.sessions.save('session-1', 'user-1', 'V Session', 'persona', 'v_researcher');
212
+ * const session = await storage.sessions.get('session-1');
213
+ * const allSessions = await storage.sessions.list('user-1', { limit: 25 });
214
+ * ```
215
+ */
216
+ get sessions(): {
217
+ /**
218
+ * Saves a session (creates or updates).
219
+ */
220
+ save: (id: string, userId: string, displayName: string, targetType: "persona" | "agency", targetId: string, metadata?: Record<string, any>) => Promise<void>;
221
+ /**
222
+ * Gets a session by ID.
223
+ */
224
+ get: (id: string) => Promise<{
225
+ id: string;
226
+ user_id: string;
227
+ display_name: string;
228
+ target_type: "persona" | "agency";
229
+ target_id: string;
230
+ created_at: number;
231
+ updated_at: number;
232
+ metadata: string;
233
+ } | null>;
234
+ /**
235
+ * Lists sessions for a user, ordered by most recent first.
236
+ */
237
+ list: (userId: string, options?: {
238
+ limit?: number;
239
+ offset?: number;
240
+ targetType?: "persona" | "agency";
241
+ }) => Promise<{
242
+ id: string;
243
+ user_id: string;
244
+ display_name: string;
245
+ target_type: "persona" | "agency";
246
+ target_id: string;
247
+ created_at: number;
248
+ updated_at: number;
249
+ metadata: string;
250
+ }[]>;
251
+ /**
252
+ * Deletes a session.
253
+ */
254
+ delete: (id: string) => Promise<void>;
255
+ };
256
+ /**
257
+ * Personas API with typed query builders.
258
+ *
259
+ * @example
260
+ * ```typescript
261
+ * await storage.personas.cache('v_researcher', 'V', personaDefinition);
262
+ * const persona = await storage.personas.get('v_researcher');
263
+ * const allPersonas = await storage.personas.list();
264
+ * ```
265
+ */
266
+ get personas(): {
267
+ /**
268
+ * Caches a persona definition (creates or updates).
269
+ */
270
+ cache: (id: string, displayName: string, definition: any) => Promise<void>;
271
+ /**
272
+ * Gets a persona by ID.
273
+ */
274
+ get: (id: string) => Promise<{
275
+ definition: any;
276
+ id: string;
277
+ display_name: string;
278
+ description: string;
279
+ created_at: number;
280
+ updated_at: number;
281
+ } | null>;
282
+ /**
283
+ * Lists all personas, ordered by display name.
284
+ */
285
+ list: () => Promise<{
286
+ definition: any;
287
+ id: string;
288
+ display_name: string;
289
+ description: string;
290
+ created_at: number;
291
+ updated_at: number;
292
+ }[]>;
293
+ /**
294
+ * Deletes a persona.
295
+ */
296
+ delete: (id: string) => Promise<void>;
297
+ };
298
+ }
299
+ /**
300
+ * Creates an AgentOS-optimized storage adapter with auto-detection and schema setup.
301
+ *
302
+ * This is the recommended way to use sql-storage-adapter with AgentOS.
303
+ * It automatically:
304
+ * 1. Detects the best storage adapter for the current platform
305
+ * 2. Creates AgentOS-specific tables (conversations, sessions, personas, etc.)
306
+ * 3. Provides typed query builders for common operations
307
+ * 4. Handles graceful degradation (e.g., IndexedDB → sql.js)
308
+ *
309
+ * @param config Configuration for platform, persistence, and features
310
+ * @returns Initialized AgentOSStorageAdapter
311
+ *
312
+ * @example
313
+ * ```typescript
314
+ * const storage = await createAgentOSStorage({ platform: 'auto' });
315
+ * const agentos = new AgentOS();
316
+ * await agentos.initialize({ storageAdapter: storage.getAdapter() });
317
+ * ```
318
+ */
319
+ export declare function createAgentOSStorage(config?: AgentOSStorageConfig): Promise<AgentOSStorageAdapter>;
320
+ //# sourceMappingURL=AgentOSStorageAdapter.d.ts.map