saico 2.9.1 → 2.9.2

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.
Files changed (3) hide show
  1. package/README.md +10 -6
  2. package/package.json +1 -1
  3. package/saico.js +25 -16
package/README.md CHANGED
@@ -267,20 +267,24 @@ const restored = await Saico.restore(agent.id, { store: 'sessions' });
267
267
 
268
268
  ## Database Access
269
269
 
270
- Saico provides backend-agnostic DB methods. Configure via `Saico.registerBackend('dynamodb', config)` (library-level), `opt.dynamodb` (instance-level auto-creates adapter), or `opt.db` (any adapter). Table name is required on every call. Child Saico instances without their own DB inherit the parent's adapter automatically via `_getDb()`, which also falls back to the registered backend.
270
+ Saico provides backend-agnostic DB methods. Configure via `Saico.registerBackend('dynamodb', config)` (library-level), `opt.dynamodb` (instance-level auto-creates adapter), or `opt.db` (any adapter). Key, key value, and table default to `'id'`, `this.id`, and `this._storeName` so operating on own record is a one-liner. Child Saico instances inherit the parent's adapter via `_getDb()`, which also falls back to the registered backend.
271
271
 
272
272
  ```js
273
- // CRUD — table name required on every call
273
+ // CRUD — shorthand (defaults: key='id', value=this.id, table=this._storeName)
274
+ const me = await agent.dbGetItem(); // get own record
275
+ await agent.dbDeleteItem(); // delete own record
276
+ // Explicit
274
277
  await agent.dbPutItem({ id: '123', name: 'test' }, 'my-table');
275
278
  const item = await agent.dbGetItem('id', '123', 'my-table');
276
279
  await agent.dbDeleteItem('id', '123', 'my-table');
277
280
  const items = await agent.dbQuery('email-index', 'email', 'user@test.com', 'my-table');
278
281
  const all = await agent.dbGetAll('my-table');
279
282
 
280
- // Updates
281
- await agent.dbUpdate('id', '123', 'status', 'active', 'my-table');
282
- await agent.dbUpdatePath('id', '123', [{ key: 'nested' }], 'field', 'value', 'my-table');
283
- await agent.dbListAppend('id', '123', 'tags', 'new-tag', 'my-table');
283
+ // Updates — setKey, item first; key, keyValue, table last (with defaults)
284
+ await agent.dbUpdate('status', 'active'); // update own record
285
+ await agent.dbUpdate('status', 'active', 'id', '123', 'my-table');
286
+ await agent.dbUpdatePath([{ key: 'nested' }], 'field', 'value');
287
+ await agent.dbListAppend('tags', 'new-tag');
284
288
 
285
289
  // Counters
286
290
  const nextId = await agent.dbNextCounterId('OrderId', 'counters');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saico",
3
- "version": "2.9.1",
3
+ "version": "2.9.2",
4
4
  "main": "index.js",
5
5
  "type": "commonjs",
6
6
  "description": "Hierarchical AI Conversation Orchestrator - Task hierarchy with conversation contexts",
package/saico.js CHANGED
@@ -38,7 +38,8 @@ class Saico {
38
38
  * @param {boolean} [opt.redis=true] - Set false to skip Redis proxy
39
39
  * @param {boolean} [opt.createQ] - Create message Q on activate()
40
40
  * @param {boolean} [opt.isolate] - Isolate: don't aggregate from ancestors
41
- * @param {Object} [opt.dynamodb] - DynamoDB config { region, credentials: { accessKeyId, secretAccessKey }, client }
41
+ * @param {Object} [opt.dynamodb] - DynamoDB config { region, credentials: { accessKeyId, secretAccessKey },
42
+ * client }
42
43
  * @param {Object} [opt.db] - Pluggable DB backend
43
44
  * @param {string} [opt.store] - Table name for instance persistence
44
45
  * @param {Object} [opt.userData] - Initial user data
@@ -46,7 +47,8 @@ class Saico {
46
47
  */
47
48
  constructor(opt = {}) {
48
49
  // Internal properties (underscore-prefixed, not persisted to Redis)
49
- this.id = opt.id || crypto.randomBytes(8).toString('hex');
50
+ this.name = opt.name || this.constructor.name || 'saico';
51
+ this.id = opt.id || this._genId();
50
52
  this._task = null;
51
53
  this._storeName = (typeof opt.store === 'string') ? opt.store : null;
52
54
  this._opt = opt;
@@ -57,7 +59,6 @@ class Saico {
57
59
  this.msgs_id = null;
58
60
 
59
61
  // Public configuration
60
- this.name = opt.name || this.constructor.name || 'saico';
61
62
  this.prompt = opt.prompt || '';
62
63
  this.functions = opt.functions || null;
63
64
  this.createQ = opt.createQ || false;
@@ -500,6 +501,14 @@ class Saico {
500
501
  };
501
502
  }
502
503
 
504
+ /**
505
+ * Generate an id. Called by constructor when opt.id is not provided.
506
+ * Overridable by subclasses for custom ID schemes.
507
+ */
508
+ _genId() {
509
+ return crypto.randomBytes(8).toString('hex');
510
+ }
511
+
503
512
  /**
504
513
  * Save instance state to registered backend under _storeName.
505
514
  */
@@ -537,23 +546,23 @@ class Saico {
537
546
  throw new Error('No DB backend configured. Call Saico.registerBackend() or set opt.db.');
538
547
  }
539
548
 
540
- async dbPutItem(item, table) {
549
+ async dbPutItem(item, table = this._storeName) {
541
550
  const db = this._getDb();
542
551
  return db.put(item, table);
543
552
  }
544
553
 
545
- async dbGetItem(key, value, table) {
554
+ async dbGetItem(key = 'id', value = this.id, table = this._storeName) {
546
555
  const db = this._getDb();
547
556
  const result = await db.get(key, value, table);
548
557
  return result ? this._deserializeRecord(result) : result;
549
558
  }
550
559
 
551
- async dbDeleteItem(key, value, table) {
560
+ async dbDeleteItem(key = 'id', value = this.id, table = this._storeName) {
552
561
  const db = this._getDb();
553
562
  return db.delete(key, value, table);
554
563
  }
555
564
 
556
- async dbQuery(index, key, value, table) {
565
+ async dbQuery(index, key, value, table = this._storeName) {
557
566
  const db = this._getDb();
558
567
  const results = await db.query(index, key, value, table);
559
568
  return Array.isArray(results)
@@ -561,7 +570,7 @@ class Saico {
561
570
  : results;
562
571
  }
563
572
 
564
- async dbGetAll(table) {
573
+ async dbGetAll(table = this._storeName) {
565
574
  const db = this._getDb();
566
575
  const results = await db.getAll(table);
567
576
  return Array.isArray(results)
@@ -569,42 +578,42 @@ class Saico {
569
578
  : results;
570
579
  }
571
580
 
572
- async dbUpdate(key, keyValue, setKey, item, table) {
581
+ async dbUpdate(setKey, item, key = 'id', keyValue = this.id, table = this._storeName) {
573
582
  const db = this._getDb();
574
583
  return db.update(key, keyValue, setKey, item, table);
575
584
  }
576
585
 
577
- async dbUpdatePath(key, keyValue, path, setKey, item, table) {
586
+ async dbUpdatePath(path, setKey, item, key = 'id', keyValue = this.id, table = this._storeName) {
578
587
  const db = this._getDb();
579
588
  return db.updatePath(key, keyValue, path, setKey, item, table);
580
589
  }
581
590
 
582
- async dbListAppend(key, keyValue, setKey, item, table) {
591
+ async dbListAppend(setKey, item, key = 'id', keyValue = this.id, table = this._storeName) {
583
592
  const db = this._getDb();
584
593
  return db.listAppend(key, keyValue, setKey, item, table);
585
594
  }
586
595
 
587
- async dbListAppendPath(key, keyValue, path, setKey, item, table) {
596
+ async dbListAppendPath(path, setKey, item, key = 'id', keyValue = this.id, table = this._storeName) {
588
597
  const db = this._getDb();
589
598
  return db.listAppendPath(key, keyValue, path, setKey, item, table);
590
599
  }
591
600
 
592
- async dbNextCounterId(counter, table) {
601
+ async dbNextCounterId(counter, table = this._storeName) {
593
602
  const db = this._getDb();
594
603
  return db.nextCounterId(counter, table);
595
604
  }
596
605
 
597
- async dbGetCounterValue(counter, table) {
606
+ async dbGetCounterValue(counter, table = this._storeName) {
598
607
  const db = this._getDb();
599
608
  return db.getCounterValue(counter, table);
600
609
  }
601
610
 
602
- async dbSetCounterValue(counter, value, table) {
611
+ async dbSetCounterValue(counter, value, table = this._storeName) {
603
612
  const db = this._getDb();
604
613
  return db.setCounterValue(counter, value, table);
605
614
  }
606
615
 
607
- async dbCountItems(table) {
616
+ async dbCountItems(table = this._storeName) {
608
617
  const db = this._getDb();
609
618
  return db.countItems(table);
610
619
  }