@personize/sdk 0.6.2 → 0.6.4

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 CHANGED
@@ -285,6 +285,47 @@ for (const [recordId, props] of Object.entries(found.data?.records ?? {})) {
285
285
  }
286
286
  // Note: 'email' and 'company-name' must match the property names in your collection definition
287
287
 
288
+ // --- Advanced Search Patterns ---
289
+
290
+ // Key-only lookup: find a record by email without needing property conditions
291
+ const byEmail = await client.memory.search({
292
+ email: 'sarah@acme.com',
293
+ returnRecords: true,
294
+ });
295
+
296
+ // Key-only lookup: find a record by custom key (no groups needed)
297
+ const byStudentNumber = await client.memory.search({
298
+ type: 'Student',
299
+ customKeyName: 'studentNumber',
300
+ customKeyValue: 'S-2024-1234',
301
+ returnRecords: true,
302
+ });
303
+
304
+ // Secondary key: find Students where email is a secondary attribute (not the primary key)
305
+ // Works because memorize stores all CRM keys on every LanceDB row
306
+ const studentByEmail = await client.memory.search({
307
+ type: 'Student',
308
+ email: 'alice@university.edu',
309
+ returnRecords: true,
310
+ });
311
+
312
+ // Cross-type search: find ALL records with this email across ALL entity types
313
+ // Returns Contacts, Students, Employees — whatever has this email
314
+ const crossType = await client.memory.search({
315
+ email: 'john@acme.com',
316
+ returnRecords: true,
317
+ });
318
+
319
+ // Property-value lookup: find records by a stored property (e.g. LinkedIn URL)
320
+ // Use this when the lookup key is a property value, not a CRM identifier
321
+ const byLinkedIn = await client.memory.search({
322
+ type: 'Contact',
323
+ returnRecords: true,
324
+ groups: [{
325
+ conditions: [{ property: 'linkedin_url', operator: 'EQ', value: 'https://linkedin.com/in/johndoe' }],
326
+ }],
327
+ });
328
+
288
329
  // Batch sync — unified call with per-property extractMemories control
289
330
  // IMPORTANT: Set extractMemories: true on rich text fields (notes, transcripts, descriptions)
290
331
  // to enable AI extraction and semantic search. Without it, only structured storage occurs.
@@ -502,7 +543,23 @@ const client = new Personize({
502
543
  });
503
544
  ```
504
545
 
505
- ## Migration from 0.5.x
546
+ ## Migration from 0.6.2
547
+
548
+ **New in 0.6.3:**
549
+
550
+ | Feature | Details |
551
+ | :--- | :--- |
552
+ | `evaluationCriteria` on `PromptOptions` | Compatibility alias for `evaluate: { criteria, serverSide: true }` |
553
+ | `message` on `RecallOptions` / `SmartRecallOptions` | Compatibility alias for `query` |
554
+ | Legacy `memory.recall()` routing | If you call `recall()` with legacy advanced-recall-style inputs (`message`, `limit`, omitted `type`, collection-name scoping), the SDK routes to `/smart-recall` automatically |
555
+ | Shorthand semantic `memory.search()` | `search({ query, limit, collectionName })` is accepted and routed to `/smart-recall` when no filter groups are provided |
556
+ | `collectionName` / `collectionNames` on `memorize()` | Collection names are resolved client-side into `collectionIds` |
557
+ | Legacy collection payload aliases | `collections.create()` now accepts `name`, `slug`, `description`, array `options`, and `updateSemantics` |
558
+ | `records` shorthand on `memorizeBatch()` | Accepts record-style input and normalizes it client-side into `memorize()` + `/batch-memorize` calls |
559
+
560
+ See [SDK_0_6_3_COMPATIBILITY_CHANGES.md](SDK_0_6_3_COMPATIBILITY_CHANGES.md) for the full design notes and tradeoffs.
561
+
562
+ ## Migration from 0.5.x
506
563
 
507
564
  **New in 0.6.0:**
508
565
 
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { PersonizeConfig, ApiResponse, MeResponse, TestResponse, ListOptions, GuidelinesResponse, GuidelineSectionOptions, GuidelineUpdatePayload, GuidelineCreatePayload, GuidelineHistoryResponse, GuidelineHistoryOptions, CollectionsResponse, CollectionCreatePayload, CollectionUpdatePayload, CollectionHistoryOptions, CollectionHistoryResponse, SmartGuidelinesOptions, SmartGuidelinesResponse, PromptOptions, PromptResponse, AgentRunOptions, AgentResponse, MemorizeOptions, SmartRecallOptions, RecallOptions, SearchOptions, SearchResponse, BatchMemorizeOptions, SmartDigestOptions, SmartDigestResponse, EvaluateMemorizationOptions, EvaluateMemorizationResponse } from './types';
1
+ import { PersonizeConfig, ApiResponse, MeResponse, TestResponse, ListOptions, GuidelinesResponse, GuidelineSectionOptions, GuidelineUpdatePayload, GuidelineCreatePayload, GuidelineHistoryResponse, GuidelineHistoryOptions, CollectionsResponse, CollectionCreatePayload, CollectionUpdatePayload, CollectionHistoryOptions, CollectionHistoryResponse, SmartGuidelinesOptions, SmartGuidelinesResponse, PromptOptions, PromptResponse, AgentRunOptions, AgentResponse, MemorizeOptions, SmartRecallOptions, RecallOptions, RecallResponse, SearchOptions, SearchResponse, BatchMemorizeOptions, SmartDigestOptions, SmartDigestResponse, EvaluateMemorizationOptions, EvaluateMemorizationResponse } from './types';
2
2
  export declare class Personize {
3
3
  private client;
4
4
  private _organizationId?;
@@ -8,6 +8,26 @@ export declare class Personize {
8
8
  constructor(config: PersonizeConfig);
9
9
  private resolveIdentity;
10
10
  private getOrganizationId;
11
+ private normalizePropertyOptions;
12
+ private inferEntityTypeFromKeys;
13
+ private listAllCollections;
14
+ private resolveCollectionIdsByName;
15
+ private normalizeCollectionCreatePayload;
16
+ private attachArrayMetadata;
17
+ private normalizeGuidelinesListResponse;
18
+ private normalizeCollectionsListResponse;
19
+ private normalizePromptOptions;
20
+ private normalizeMemorizeOptions;
21
+ private normalizeSmartRecallOptions;
22
+ private isLegacyRecallRequest;
23
+ private normalizeLegacyRecallToSmartRecall;
24
+ private normalizeRecallOptions;
25
+ private buildSearchGroupsFromFilters;
26
+ private normalizeSearchRequest;
27
+ private normalizeSearchResponse;
28
+ private normalizeRecallResponse;
29
+ private isBatchRecordProperty;
30
+ private memorizeBatchFromRecords;
11
31
  /**
12
32
  * GET /api/v1/test — Verify API key is valid. Returns request metadata and resolved identity.
13
33
  */
@@ -111,11 +131,11 @@ export declare class Personize {
111
131
  * POST /api/v1/smart-recall — Advanced recall with reflection (RAG).
112
132
  * Supports reflection loops for improved coverage, answer generation, and entity scoping.
113
133
  */
114
- smartRecall: (data: SmartRecallOptions) => Promise<ApiResponse>;
134
+ smartRecall: (data: SmartRecallOptions) => Promise<ApiResponse<RecallResponse>>;
115
135
  /**
116
136
  * POST /api/v1/recall — Direct memory lookup (no reflection).
117
137
  */
118
- recall: (data: RecallOptions) => Promise<ApiResponse>;
138
+ recall: (data: RecallOptions) => Promise<ApiResponse<RecallResponse>>;
119
139
  /**
120
140
  * POST /api/v1/search — Filter and search records by property conditions.
121
141
  * Returns matching record IDs with optional property values and memories.
package/dist/client.js CHANGED
@@ -26,7 +26,11 @@ class Personize {
26
26
  if (options?.excludeTags)
27
27
  params.excludeTags = Array.isArray(options.excludeTags) ? options.excludeTags.join(',') : options.excludeTags;
28
28
  const response = await this.client.get('/api/v1/guidelines', { params });
29
- return response.data;
29
+ const responseData = response.data;
30
+ if (responseData?.data) {
31
+ responseData.data = this.normalizeGuidelinesListResponse(responseData.data);
32
+ }
33
+ return responseData;
30
34
  },
31
35
  /**
32
36
  * GET /api/v1/guidelines/:id/structure — Get guideline headings
@@ -100,13 +104,18 @@ class Personize {
100
104
  if (options?.excludeTags)
101
105
  params.excludeTags = Array.isArray(options.excludeTags) ? options.excludeTags.join(',') : options.excludeTags;
102
106
  const response = await this.client.get('/api/v1/collections', { params });
103
- return response.data;
107
+ const responseData = response.data;
108
+ if (responseData?.data) {
109
+ responseData.data = this.normalizeCollectionsListResponse(responseData.data);
110
+ }
111
+ return responseData;
104
112
  },
105
113
  /**
106
114
  * POST /api/v1/collections — Create a new property collection
107
115
  */
108
116
  create: async (payload) => {
109
- const response = await this.client.post('/api/v1/collections', payload);
117
+ const normalizedPayload = await this.normalizeCollectionCreatePayload(payload);
118
+ const response = await this.client.post('/api/v1/collections', normalizedPayload);
110
119
  return response.data;
111
120
  },
112
121
  /**
@@ -156,7 +165,8 @@ class Personize {
156
165
  * Use `memorize` to auto-save outputs and tool results to memory.
157
166
  */
158
167
  prompt: async (options) => {
159
- const response = await this.client.post('/api/v1/prompt', options);
168
+ const normalizedOptions = this.normalizePromptOptions(options);
169
+ const response = await this.client.post('/api/v1/prompt', normalizedOptions);
160
170
  return response.data;
161
171
  },
162
172
  };
@@ -201,7 +211,35 @@ class Personize {
201
211
  * Performs structured property extraction and free-form memory creation.
202
212
  */
203
213
  memorize: async (data) => {
204
- const response = await this.client.post('/api/v1/memorize', data);
214
+ if (data.properties && Object.keys(data.properties).length > 0) {
215
+ return this.memorizeBatchFromRecords({
216
+ source: 'SDK memorize compatibility',
217
+ enhanced: data.enhanced,
218
+ records: [{
219
+ content: data.content,
220
+ email: data.email,
221
+ website_url: data.website_url,
222
+ record_id: data.record_id,
223
+ type: data.type,
224
+ customKeyName: data.customKeyName,
225
+ customKeyValue: data.customKeyValue,
226
+ collectionId: data.collectionIds?.[0],
227
+ collectionName: data.collectionName,
228
+ properties: data.properties,
229
+ tags: data.tags,
230
+ enhanced: data.enhanced,
231
+ timestamp: data.timestamp,
232
+ speaker: data.speaker,
233
+ }],
234
+ mapping: {
235
+ entityType: data.type || 'Record',
236
+ properties: {},
237
+ },
238
+ rows: [],
239
+ });
240
+ }
241
+ const normalizedData = await this.normalizeMemorizeOptions(data);
242
+ const response = await this.client.post('/api/v1/memorize', normalizedData);
205
243
  return response.data;
206
244
  },
207
245
  /**
@@ -209,23 +247,63 @@ class Personize {
209
247
  * Supports reflection loops for improved coverage, answer generation, and entity scoping.
210
248
  */
211
249
  smartRecall: async (data) => {
212
- const response = await this.client.post('/api/v1/smart-recall', data);
213
- return response.data;
250
+ const normalizedData = this.normalizeSmartRecallOptions(data);
251
+ const response = await this.client.post('/api/v1/smart-recall', normalizedData);
252
+ const responseData = response.data;
253
+ if (responseData?.data) {
254
+ responseData.data = this.normalizeRecallResponse(responseData.data);
255
+ }
256
+ return responseData;
214
257
  },
215
258
  /**
216
259
  * POST /api/v1/recall — Direct memory lookup (no reflection).
217
260
  */
218
261
  recall: async (data) => {
219
- const response = await this.client.post('/api/v1/recall', data);
220
- return response.data;
262
+ if (this.isLegacyRecallRequest(data)) {
263
+ const compatPayload = this.normalizeLegacyRecallToSmartRecall(data);
264
+ const response = await this.client.post('/api/v1/smart-recall', compatPayload);
265
+ const responseData = response.data;
266
+ if (responseData?.data) {
267
+ responseData.data = this.normalizeRecallResponse(responseData.data);
268
+ }
269
+ return responseData;
270
+ }
271
+ const normalizedData = this.normalizeRecallOptions(data);
272
+ const response = await this.client.post('/api/v1/recall', normalizedData);
273
+ const responseData = response.data;
274
+ if (responseData?.data) {
275
+ responseData.data = this.normalizeRecallResponse(responseData.data);
276
+ }
277
+ return responseData;
221
278
  },
222
279
  /**
223
280
  * POST /api/v1/search — Filter and search records by property conditions.
224
281
  * Returns matching record IDs with optional property values and memories.
225
282
  */
226
283
  search: async (data) => {
227
- const response = await this.client.post('/api/v1/search', data);
228
- return response.data;
284
+ const normalizedRequest = await this.normalizeSearchRequest(data);
285
+ if (normalizedRequest.mode === 'smartRecall') {
286
+ const response = await this.client.post('/api/v1/smart-recall', normalizedRequest.payload);
287
+ const responseData = response.data;
288
+ if (responseData?.data) {
289
+ const recallData = this.normalizeRecallResponse(responseData.data);
290
+ responseData.data = this.attachArrayMetadata([...(recallData || [])], {
291
+ recordIds: [],
292
+ totalMatched: recallData?.length || 0,
293
+ page: 1,
294
+ pageSize: recallData?.length || 0,
295
+ totalPages: 1,
296
+ results: recallData ? [...recallData] : [],
297
+ });
298
+ }
299
+ return responseData;
300
+ }
301
+ const response = await this.client.post('/api/v1/search', normalizedRequest.payload);
302
+ const responseData = response.data;
303
+ if (responseData?.data) {
304
+ responseData.data = this.normalizeSearchResponse(responseData.data);
305
+ }
306
+ return responseData;
229
307
  },
230
308
  /**
231
309
  * POST /api/v1/batch-memorize — Unified batch sync with per-property extractMemories flag.
@@ -233,6 +311,9 @@ class Personize {
233
311
  * Properties without it (or false) are stored as structured data only.
234
312
  */
235
313
  memorizeBatch: async (data) => {
314
+ if (data.records?.length) {
315
+ return this.memorizeBatchFromRecords(data);
316
+ }
236
317
  const { organizationId, userId } = await this.resolveIdentity();
237
318
  const response = await this.client.post('/api/v1/batch-memorize', {
238
319
  ...data,
@@ -312,6 +393,387 @@ class Personize {
312
393
  const { organizationId } = await this.resolveIdentity();
313
394
  return organizationId;
314
395
  }
396
+ normalizePropertyOptions(options) {
397
+ if (!options)
398
+ return undefined;
399
+ return Array.isArray(options) ? options.join(',') : options;
400
+ }
401
+ inferEntityTypeFromKeys(input) {
402
+ if (input.primaryKeyField === 'email' || input.email)
403
+ return 'Contact';
404
+ if (input.primaryKeyField === 'website' || input.primaryKeyField === 'website_url' || input.website_url || input.websiteUrl) {
405
+ return 'Company';
406
+ }
407
+ return undefined;
408
+ }
409
+ async listAllCollections() {
410
+ const collections = [];
411
+ let nextToken;
412
+ do {
413
+ const response = await this.client.get('/api/v1/collections', {
414
+ params: {
415
+ limit: 100,
416
+ nextToken,
417
+ summary: 'true',
418
+ },
419
+ });
420
+ const data = response.data?.data;
421
+ for (const action of data?.actions ?? []) {
422
+ const payload = action?.payload ?? {};
423
+ if (payload.collectionId && payload.collectionName) {
424
+ collections.push({
425
+ collectionId: String(payload.collectionId),
426
+ collectionName: String(payload.collectionName),
427
+ });
428
+ }
429
+ }
430
+ nextToken = data?.nextToken;
431
+ } while (nextToken);
432
+ return collections;
433
+ }
434
+ async resolveCollectionIdsByName(names) {
435
+ if (!names?.length)
436
+ return undefined;
437
+ const normalizedNames = names.map((name) => name.trim().toLowerCase()).filter(Boolean);
438
+ if (!normalizedNames.length)
439
+ return undefined;
440
+ const collections = await this.listAllCollections();
441
+ const ids = normalizedNames.map((target) => {
442
+ const match = collections.find((collection) => collection.collectionName.toLowerCase() === target);
443
+ return match?.collectionId;
444
+ }).filter((value) => Boolean(value));
445
+ return ids.length ? Array.from(new Set(ids)) : undefined;
446
+ }
447
+ async normalizeCollectionCreatePayload(payload) {
448
+ const normalizedProperties = payload.properties?.map((property) => ({
449
+ ...property,
450
+ options: this.normalizePropertyOptions(property.options),
451
+ update: property.update ?? (property.updateSemantics ? property.updateSemantics !== 'append' : undefined),
452
+ }));
453
+ return {
454
+ collectionName: payload.collectionName || payload.name || '',
455
+ collectionId: payload.collectionId || payload.slug,
456
+ definition: payload.definition || payload.description,
457
+ entityType: payload.entityType || this.inferEntityTypeFromKeys({ primaryKeyField: payload.primaryKeyField }),
458
+ properties: normalizedProperties,
459
+ status: payload.status,
460
+ };
461
+ }
462
+ attachArrayMetadata(items, metadata) {
463
+ return Object.assign(items, metadata);
464
+ }
465
+ normalizeGuidelinesListResponse(data) {
466
+ if (!data?.actions)
467
+ return data;
468
+ const items = data.actions.map((action) => ({
469
+ id: action.id,
470
+ type: action.type,
471
+ slug: typeof action.payload.name === 'string' ? action.payload.name : undefined,
472
+ ...action.payload,
473
+ }));
474
+ return this.attachArrayMetadata(items, data);
475
+ }
476
+ normalizeCollectionsListResponse(data) {
477
+ if (!data?.actions)
478
+ return data;
479
+ const items = data.actions.map((action) => ({
480
+ id: action.id,
481
+ type: action.type,
482
+ name: action.payload.collectionName,
483
+ slug: action.payload.collectionId,
484
+ ...action.payload,
485
+ }));
486
+ return this.attachArrayMetadata(items, data);
487
+ }
488
+ normalizePromptOptions(options) {
489
+ if (!options.evaluationCriteria || options.evaluate) {
490
+ const { evaluationCriteria, ...rest } = options;
491
+ return rest;
492
+ }
493
+ const { evaluationCriteria, ...rest } = options;
494
+ return {
495
+ ...rest,
496
+ evaluate: {
497
+ criteria: evaluationCriteria,
498
+ serverSide: true,
499
+ },
500
+ };
501
+ }
502
+ async normalizeMemorizeOptions(data) {
503
+ const { collectionName, collectionNames, properties, ...rest } = data;
504
+ const requestedCollectionNames = [
505
+ ...(collectionNames || []),
506
+ ...(collectionName ? [collectionName] : []),
507
+ ];
508
+ const collectionIds = rest.collectionIds?.length
509
+ ? rest.collectionIds
510
+ : await this.resolveCollectionIdsByName(requestedCollectionNames);
511
+ return {
512
+ ...rest,
513
+ collectionIds,
514
+ properties,
515
+ };
516
+ }
517
+ normalizeSmartRecallOptions(data) {
518
+ const { message, collectionName, ...rest } = data;
519
+ return {
520
+ ...rest,
521
+ query: data.query || message || '',
522
+ collectionNames: data.collectionNames || (collectionName ? [collectionName] : undefined),
523
+ };
524
+ }
525
+ isLegacyRecallRequest(data) {
526
+ return Boolean(data.message ||
527
+ data.limit != null ||
528
+ data.collectionName ||
529
+ data.collectionNames?.length ||
530
+ !data.type);
531
+ }
532
+ normalizeLegacyRecallToSmartRecall(data) {
533
+ return {
534
+ query: data.query || data.message || '',
535
+ limit: data.limit,
536
+ email: data.email,
537
+ website_url: data.website_url,
538
+ websiteUrl: data.websiteUrl,
539
+ record_id: data.record_id,
540
+ recordId: data.recordId,
541
+ type: data.type || this.inferEntityTypeFromKeys({
542
+ email: data.email,
543
+ website_url: data.website_url,
544
+ websiteUrl: data.websiteUrl,
545
+ }),
546
+ customKeyName: data.customKeyName,
547
+ customKeyValue: data.customKeyValue,
548
+ filters: data.filters,
549
+ collectionNames: data.collectionNames || (data.collectionName ? [data.collectionName] : undefined),
550
+ };
551
+ }
552
+ normalizeRecallOptions(data) {
553
+ const { message, limit, collectionName, collectionNames, ...rest } = data;
554
+ return {
555
+ ...rest,
556
+ query: data.query || message || '',
557
+ type: data.type || this.inferEntityTypeFromKeys({
558
+ email: rest.email,
559
+ website_url: rest.website_url,
560
+ websiteUrl: rest.websiteUrl,
561
+ }),
562
+ };
563
+ }
564
+ buildSearchGroupsFromFilters(filters) {
565
+ if (!filters)
566
+ return undefined;
567
+ const conditions = Object.entries(filters)
568
+ .filter(([, value]) => value !== undefined)
569
+ .flatMap(([property, value]) => {
570
+ if (Array.isArray(value)) {
571
+ return value.map((item) => ({
572
+ property,
573
+ operator: 'contains',
574
+ value: item,
575
+ }));
576
+ }
577
+ return [{
578
+ property,
579
+ operator: 'equals',
580
+ value: value,
581
+ }];
582
+ });
583
+ return conditions.length ? [{ conditions }] : undefined;
584
+ }
585
+ async normalizeSearchRequest(data) {
586
+ const collectionNames = data.collectionNames || (data.collectionName ? [data.collectionName] : undefined);
587
+ if (data.query && !data.groups?.length) {
588
+ return {
589
+ mode: 'smartRecall',
590
+ payload: {
591
+ query: data.query,
592
+ limit: data.limit || data.pageSize,
593
+ type: data.type,
594
+ email: data.email,
595
+ websiteUrl: data.websiteUrl,
596
+ recordId: data.recordId,
597
+ customKeyName: data.customKeyName,
598
+ customKeyValue: data.customKeyValue,
599
+ collectionNames,
600
+ filters: data.filters,
601
+ },
602
+ };
603
+ }
604
+ const collectionIds = data.collectionIds?.length
605
+ ? data.collectionIds
606
+ : await this.resolveCollectionIdsByName(collectionNames);
607
+ return {
608
+ mode: 'search',
609
+ payload: {
610
+ type: data.type,
611
+ email: data.email,
612
+ websiteUrl: data.websiteUrl,
613
+ recordId: data.recordId,
614
+ customKeyName: data.customKeyName,
615
+ customKeyValue: data.customKeyValue,
616
+ collectionIds,
617
+ groups: data.groups || this.buildSearchGroupsFromFilters(data.filters),
618
+ pageSize: data.pageSize || data.limit,
619
+ page: data.page,
620
+ countOnly: data.countOnly,
621
+ returnRecords: data.returnRecords,
622
+ includeMemories: data.includeMemories,
623
+ dataSource: data.dataSource,
624
+ },
625
+ };
626
+ }
627
+ normalizeSearchResponse(data) {
628
+ if (!data)
629
+ return data;
630
+ const results = data.recordIds.map((recordId) => ({
631
+ recordId,
632
+ mainProperties: data.mainProperties?.[recordId],
633
+ record: data.records?.[recordId],
634
+ memories: data.memories?.[recordId],
635
+ }));
636
+ return this.attachArrayMetadata(results, {
637
+ ...data,
638
+ results: [...results],
639
+ });
640
+ }
641
+ normalizeRecallResponse(data) {
642
+ if (!data)
643
+ return undefined;
644
+ const source = Array.isArray(data) ? { results: data } : data;
645
+ const rawResults = Array.isArray(source.results)
646
+ ? source.results
647
+ : Array.isArray(source.memories)
648
+ ? source.memories
649
+ : [];
650
+ const results = rawResults.map((entry) => {
651
+ if (typeof entry !== 'object' || entry === null) {
652
+ return { content: String(entry), memory: String(entry) };
653
+ }
654
+ const record = entry;
655
+ const content = typeof record.content === 'string'
656
+ ? record.content
657
+ : typeof record.memory === 'string'
658
+ ? record.memory
659
+ : typeof record.text === 'string'
660
+ ? record.text
661
+ : undefined;
662
+ return {
663
+ ...record,
664
+ content,
665
+ memory: typeof record.memory === 'string' ? record.memory : content,
666
+ };
667
+ });
668
+ return this.attachArrayMetadata(results, {
669
+ ...(Array.isArray(data) ? {} : source),
670
+ results: [...results],
671
+ });
672
+ }
673
+ isBatchRecordProperty(value) {
674
+ return typeof value === 'object' && value !== null && 'value' in value;
675
+ }
676
+ async memorizeBatchFromRecords(data) {
677
+ const records = data.records || [];
678
+ if (!records.length) {
679
+ return { success: true, data: { memorized: 0 } };
680
+ }
681
+ const contentRecords = records.filter((record) => record.content);
682
+ for (const record of contentRecords) {
683
+ const normalizedMemorize = await this.normalizeMemorizeOptions({
684
+ content: String(record.content),
685
+ email: record.email,
686
+ website_url: record.website_url || record.websiteUrl,
687
+ record_id: record.record_id || record.recordId,
688
+ type: record.type,
689
+ customKeyName: record.customKeyName,
690
+ customKeyValue: record.customKeyValue,
691
+ tags: record.tags,
692
+ enhanced: record.enhanced ?? data.enhanced,
693
+ timestamp: record.timestamp,
694
+ speaker: record.speaker,
695
+ collectionNames: record.collectionName ? [record.collectionName] : undefined,
696
+ collectionIds: record.collectionId ? [record.collectionId] : undefined,
697
+ });
698
+ await this.memory.memorize(normalizedMemorize);
699
+ }
700
+ const structuredRecords = records.filter((record) => record.properties && Object.keys(record.properties).length > 0);
701
+ if (!structuredRecords.length) {
702
+ return { success: true, data: { memorized: contentRecords.length } };
703
+ }
704
+ const first = structuredRecords[0];
705
+ const entityType = first.type || this.inferEntityTypeFromKeys({
706
+ email: first.email,
707
+ website_url: first.website_url,
708
+ websiteUrl: first.websiteUrl,
709
+ }) || 'Record';
710
+ const mappingProperties = {};
711
+ const rows = structuredRecords.map((record) => {
712
+ const row = {};
713
+ if (record.email)
714
+ row.email = record.email;
715
+ if (record.website_url || record.websiteUrl)
716
+ row.website = record.website_url || record.websiteUrl;
717
+ if (record.record_id || record.recordId)
718
+ row.record_id = record.record_id || record.recordId;
719
+ if (record.customKeyValue)
720
+ row.custom_key = record.customKeyValue;
721
+ for (const [propertyName, rawProperty] of Object.entries(record.properties || {})) {
722
+ const property = this.isBatchRecordProperty(rawProperty)
723
+ ? rawProperty
724
+ : { value: rawProperty };
725
+ row[propertyName] = property.value;
726
+ if (!mappingProperties[propertyName]) {
727
+ mappingProperties[propertyName] = {
728
+ sourceField: propertyName,
729
+ collectionId: property.collectionId || record.collectionId || '',
730
+ collectionName: property.collectionName || record.collectionName || '',
731
+ extractMemories: property.extractMemories,
732
+ };
733
+ }
734
+ }
735
+ return row;
736
+ });
737
+ const unresolvedNames = Array.from(new Set(Object.values(mappingProperties)
738
+ .filter((property) => !property.collectionId && property.collectionName)
739
+ .map((property) => property.collectionName)));
740
+ const resolvedMap = new Map();
741
+ if (unresolvedNames.length) {
742
+ const collections = await this.listAllCollections();
743
+ for (const collection of collections) {
744
+ if (unresolvedNames.some((name) => name.toLowerCase() === collection.collectionName.toLowerCase())) {
745
+ resolvedMap.set(collection.collectionName.toLowerCase(), collection.collectionId);
746
+ }
747
+ }
748
+ }
749
+ for (const property of Object.values(mappingProperties)) {
750
+ if (!property.collectionId && property.collectionName) {
751
+ property.collectionId = resolvedMap.get(property.collectionName.toLowerCase()) || '';
752
+ }
753
+ if (!property.collectionId || !property.collectionName) {
754
+ throw new Error('records shorthand requires collectionId/collectionName for each structured property');
755
+ }
756
+ }
757
+ const { organizationId, userId } = await this.resolveIdentity();
758
+ const response = await this.client.post('/api/v1/batch-memorize', {
759
+ source: data.source || 'SDK records shorthand',
760
+ tier: data.tier,
761
+ dryRun: data.dryRun,
762
+ chunkSize: data.chunkSize,
763
+ mapping: {
764
+ entityType,
765
+ email: rows.some((row) => row.email) ? 'email' : undefined,
766
+ website: rows.some((row) => row.website) ? 'website' : undefined,
767
+ customKeyName: first.customKeyName,
768
+ customKey: rows.some((row) => row.custom_key) ? 'custom_key' : undefined,
769
+ properties: mappingProperties,
770
+ },
771
+ rows,
772
+ orgId: organizationId,
773
+ userId,
774
+ });
775
+ return response.data;
776
+ }
315
777
  /**
316
778
  * GET /api/v1/test — Verify API key is valid. Returns request metadata and resolved identity.
317
779
  */
package/dist/types.d.ts CHANGED
@@ -65,7 +65,18 @@ export interface GovernanceScope {
65
65
  /** Action/domain keywords that trigger inclusion (e.g., "email", "pricing", "deploy"). */
66
66
  triggerKeywords: string[];
67
67
  }
68
- export interface GuidelinesResponse {
68
+ export interface GuidelineListItem {
69
+ id: string;
70
+ type: string;
71
+ name: string;
72
+ value: string;
73
+ /** Compatibility alias commonly used by setup scripts. */
74
+ slug?: string;
75
+ /** Auto-inferred governance scope (read-only). Present when the guideline has been analyzed. */
76
+ governanceScope?: GovernanceScope;
77
+ [key: string]: unknown;
78
+ }
79
+ export interface GuidelinesResponse extends Array<GuidelineListItem> {
69
80
  actions: Array<{
70
81
  id: string;
71
82
  type: string;
@@ -107,6 +118,8 @@ export interface GuidelineCreatePayload {
107
118
  description?: string;
108
119
  tags?: string[];
109
120
  secure?: boolean;
121
+ /** Compatibility alias used by some setup scripts. */
122
+ slug?: string;
110
123
  }
111
124
  /** @deprecated Use GuidelineCreatePayload instead. */
112
125
  export type VariableCreatePayload = GuidelineCreatePayload;
@@ -142,7 +155,17 @@ export interface GuidelineHistoryOptions {
142
155
  }
143
156
  /** @deprecated Use GuidelineHistoryOptions instead. */
144
157
  export type VariableHistoryOptions = GuidelineHistoryOptions;
145
- export interface CollectionsResponse {
158
+ export interface CollectionListItem {
159
+ id: string;
160
+ type: string;
161
+ collectionName: string;
162
+ collectionId: string;
163
+ /** Compatibility aliases commonly used by setup scripts. */
164
+ name?: string;
165
+ slug?: string;
166
+ [key: string]: unknown;
167
+ }
168
+ export interface CollectionsResponse extends Array<CollectionListItem> {
146
169
  actions: Array<{
147
170
  id: string;
148
171
  type: string;
@@ -157,19 +180,34 @@ export interface CollectionsResponse {
157
180
  nextToken?: string;
158
181
  }
159
182
  export interface CollectionCreatePayload {
160
- collectionName: string;
183
+ collectionName?: string;
161
184
  collectionId?: string;
162
185
  definition?: string;
163
186
  entityType?: string;
187
+ /** Compatibility alias for collectionName. */
188
+ name?: string;
189
+ /** Compatibility alias for collectionId. */
190
+ slug?: string;
191
+ /** Compatibility alias for definition. */
192
+ description?: string;
193
+ /** Accepted for compatibility; ignored unless the API supports it. */
194
+ icon?: string;
195
+ /** Accepted for compatibility; ignored unless the API supports it. */
196
+ color?: string;
197
+ /** Accepted for compatibility; may be used to infer entityType client-side. */
198
+ primaryKeyField?: string;
164
199
  properties?: Array<{
165
200
  propertyName: string;
166
201
  propertyId?: string;
167
202
  systemName?: string;
168
203
  type?: 'text' | 'date' | 'options' | 'number' | 'boolean' | 'array';
169
- options?: string;
204
+ options?: string | string[];
170
205
  description?: string;
171
206
  autoSystem?: boolean;
172
207
  update?: boolean;
208
+ /** Compatibility alias. `append` maps to `update: false`, `replace` to `update: true`. */
209
+ updateSemantics?: 'replace' | 'append';
210
+ tags?: string[];
173
211
  status?: 'Active' | 'Deleted';
174
212
  }>;
175
213
  status?: 'Active' | 'Deleted';
@@ -183,10 +221,13 @@ export interface CollectionUpdatePayload {
183
221
  propertyName?: string;
184
222
  systemName?: string;
185
223
  type?: 'text' | 'date' | 'options' | 'number' | 'boolean' | 'array';
186
- options?: string;
224
+ options?: string | string[];
187
225
  description?: string;
188
226
  autoSystem?: boolean;
189
227
  update?: boolean;
228
+ /** Compatibility alias. `append` maps to `update: false`, `replace` to `update: true`. */
229
+ updateSemantics?: 'replace' | 'append';
230
+ tags?: string[];
190
231
  status?: 'Active' | 'Deleted';
191
232
  }>;
192
233
  status?: 'Active' | 'Deleted';
@@ -413,6 +454,8 @@ export interface PromptOptions {
413
454
  * - `{ criteria: 'sales', serverSide: true }` — server-side with preset/custom criteria
414
455
  */
415
456
  evaluate?: PromptEvaluateConfig;
457
+ /** Compatibility alias for evaluate: { criteria, serverSide: true }. */
458
+ evaluationCriteria?: string;
416
459
  /**
417
460
  * Auto-memorize extracted outputs and/or captured tool results.
418
461
  * Requires at least one identifier (email, websiteUrl, or recordId).
@@ -563,10 +606,16 @@ export interface MemorizeOptions {
563
606
  customKeyValue?: string;
564
607
  /** Enable enhanced dual extraction (structured + free-form). */
565
608
  enhanced?: boolean;
609
+ /** Compatibility shorthand for structured property writes. */
610
+ properties?: Record<string, unknown | BatchMemorizeRecordProperty>;
566
611
  /** Tags for property selection. */
567
612
  tags?: string[];
568
613
  /** Limit extraction to specific collections. */
569
614
  collectionIds?: string[];
615
+ /** Compatibility alias for a single collection name; resolved client-side when possible. */
616
+ collectionName?: string;
617
+ /** Compatibility alias for collectionIds by name; resolved client-side when possible. */
618
+ collectionNames?: string[];
570
619
  /** Max properties to select for extraction. */
571
620
  max_properties?: number;
572
621
  /** If true, extract without persisting (dry run). */
@@ -581,6 +630,8 @@ export type MemorizeProOptions = MemorizeOptions;
581
630
  export interface SmartRecallOptions {
582
631
  /** Natural-language query. */
583
632
  query: string;
633
+ /** Compatibility alias for query. */
634
+ message?: string;
584
635
  /** Max results to return (default: 10). */
585
636
  limit?: number;
586
637
  /** Minimum similarity score threshold. */
@@ -605,6 +656,8 @@ export interface SmartRecallOptions {
605
656
  collectionIds?: string[];
606
657
  /** Scope results to specific collections by name (resolved server-side, case-insensitive). */
607
658
  collectionNames?: string[];
659
+ /** Compatibility alias for a single collection name. */
660
+ collectionName?: string;
608
661
  /** Return schema-enforced property values separately from free-form memories. */
609
662
  include_property_values?: boolean;
610
663
  /** Enable reflection loop to improve recall coverage (default: true). */
@@ -636,9 +689,13 @@ export interface SmartRecallOptions {
636
689
  export type RecallProOptions = SmartRecallOptions;
637
690
  export interface RecallOptions {
638
691
  /** Natural-language query. */
639
- query: string;
640
- /** Entity type (e.g. 'Contact', 'Company'). Required by the /recall endpoint. */
641
- type: string;
692
+ query?: string;
693
+ /** Compatibility alias for query. */
694
+ message?: string;
695
+ /** Entity type (e.g. 'Contact', 'Company'). Required for direct /recall lookups. */
696
+ type?: string;
697
+ /** Compatibility alias retained for older advanced-recall call sites. */
698
+ limit?: number;
642
699
  /** CRM record ID for entity scoping. */
643
700
  record_id?: string;
644
701
  /** CRM record ID (camelCase alias). */
@@ -655,6 +712,33 @@ export interface RecallOptions {
655
712
  customKeyValue?: string;
656
713
  /** Additional filters. */
657
714
  filters?: Record<string, unknown>;
715
+ /** Compatibility alias for a single collection name. */
716
+ collectionName?: string;
717
+ /** Compatibility alias for collection scoping by name. */
718
+ collectionNames?: string[];
719
+ }
720
+ export interface RecallResultItem {
721
+ content?: string;
722
+ memory?: string;
723
+ text?: string;
724
+ createdAt?: string;
725
+ score?: number;
726
+ recordId?: string;
727
+ type?: string;
728
+ email?: string;
729
+ website_url?: string;
730
+ website?: string;
731
+ company_name?: string;
732
+ name?: string;
733
+ properties?: Record<string, PropertyValue>;
734
+ metadata?: Record<string, unknown>;
735
+ [key: string]: unknown;
736
+ }
737
+ export interface RecallResponse extends Array<RecallResultItem> {
738
+ results?: RecallResultItem[];
739
+ answer?: string;
740
+ query?: string;
741
+ [key: string]: unknown;
658
742
  }
659
743
  export interface BatchMemorizePropertyMapping {
660
744
  /** Source field name in the row data */
@@ -687,17 +771,45 @@ export interface BatchMemorizeMapping {
687
771
  }
688
772
  export interface BatchMemorizeOptions {
689
773
  /** Source system label (e.g. 'Hubspot', 'Salesforce') */
690
- source: string;
774
+ source?: string;
691
775
  /** Memorize tier: 'basic' | 'pro' | 'pro_fast' | 'ultra'. Default: 'pro'. */
692
776
  tier?: 'basic' | 'pro' | 'pro_fast' | 'ultra';
693
777
  /** Mapping configuration for the sync */
694
- mapping: BatchMemorizeMapping;
778
+ mapping?: BatchMemorizeMapping;
695
779
  /** Array of source data rows (key-value objects matching sourceField names) */
696
- rows: Record<string, unknown>[];
780
+ rows?: Record<string, unknown>[];
697
781
  /** If true, validate without writing (default: false) */
698
782
  dryRun?: boolean;
699
783
  /** Number of rows to process per chunk (default: 1) */
700
784
  chunkSize?: number;
785
+ /** Compatibility flag accepted and ignored when not needed. */
786
+ enhanced?: boolean;
787
+ /** Compatibility shorthand accepted by the SDK and normalized client-side. */
788
+ records?: BatchMemorizeRecord[];
789
+ }
790
+ export interface BatchMemorizeRecordProperty {
791
+ value: unknown;
792
+ extractMemories?: boolean;
793
+ collectionId?: string;
794
+ collectionName?: string;
795
+ }
796
+ export interface BatchMemorizeRecord {
797
+ content?: string;
798
+ email?: string;
799
+ website_url?: string;
800
+ websiteUrl?: string;
801
+ record_id?: string;
802
+ recordId?: string;
803
+ type?: string;
804
+ customKeyName?: string;
805
+ customKeyValue?: string;
806
+ collectionId?: string;
807
+ collectionName?: string;
808
+ properties?: Record<string, unknown | BatchMemorizeRecordProperty>;
809
+ tags?: string[];
810
+ enhanced?: boolean;
811
+ timestamp?: string;
812
+ speaker?: string;
701
813
  }
702
814
  export interface SmartDigestOptions {
703
815
  /** CRM record ID */
@@ -758,6 +870,8 @@ export interface SearchFilterGroup {
758
870
  conditions: SearchFilterCondition[];
759
871
  }
760
872
  export interface SearchOptions {
873
+ /** Compatibility shorthand for semantic search; routed client-side to smartRecall when groups are omitted. */
874
+ query?: string;
761
875
  /** Filter groups with conditions. To list all records, send one group with empty conditions. */
762
876
  groups?: SearchFilterGroup[];
763
877
  /** Entity type (e.g. 'Contact', 'Company'). */
@@ -768,12 +882,22 @@ export interface SearchOptions {
768
882
  websiteUrl?: string;
769
883
  /** Scope to a specific record ID. */
770
884
  recordId?: string;
885
+ /** Custom key name for custom entity types (e.g. 'studentNumber', 'linkedinUrl'). */
886
+ customKeyName?: string;
887
+ /** Custom key value (e.g. 'S-2024-1234'). Used with customKeyName to scope to a custom-keyed record. */
888
+ customKeyValue?: string;
771
889
  /** Scope to specific collections. */
772
890
  collectionIds?: string[];
891
+ /** Compatibility alias for a single collection name. */
892
+ collectionName?: string;
893
+ /** Compatibility alias for collection scoping by name. */
894
+ collectionNames?: string[];
773
895
  /** Page number (1-based, default: 1). */
774
896
  page?: number;
775
897
  /** Results per page (max 200, default: 50). */
776
898
  pageSize?: number;
899
+ /** Compatibility alias for pageSize. */
900
+ limit?: number;
777
901
  /** Return only totalMatched count. */
778
902
  countOnly?: boolean;
779
903
  /** Include property values per record. */
@@ -782,6 +906,8 @@ export interface SearchOptions {
782
906
  includeMemories?: boolean;
783
907
  /** Data source: 'lancedb' or 'snapshot' (default: 'lancedb'). */
784
908
  dataSource?: 'lancedb' | 'snapshot';
909
+ /** Compatibility shorthand filters; converted client-side to groups where possible. */
910
+ filters?: Record<string, unknown>;
785
911
  }
786
912
  /** @deprecated Use SearchOptions instead. */
787
913
  export type ExportOptions = SearchOptions;
@@ -791,7 +917,30 @@ export interface MemoryItem {
791
917
  score?: number;
792
918
  metadata?: Record<string, PropertyValue>;
793
919
  }
794
- export interface SearchResponse {
920
+ export interface SearchResultItem {
921
+ recordId?: string;
922
+ mainProperties?: Record<string, string>;
923
+ record?: Record<string, {
924
+ value: PropertyValue;
925
+ collectionId: string;
926
+ collectionName?: string;
927
+ }>;
928
+ memories?: MemoryItem[];
929
+ content?: string;
930
+ memory?: string;
931
+ email?: string;
932
+ website_url?: string;
933
+ website?: string;
934
+ company_name?: string;
935
+ name?: string;
936
+ linkedin_url?: string;
937
+ phone_number?: string;
938
+ crm_id?: string;
939
+ lead_score?: number;
940
+ properties?: Record<string, PropertyValue>;
941
+ [key: string]: unknown;
942
+ }
943
+ export interface SearchResponse extends Array<SearchResultItem> {
795
944
  recordIds: string[];
796
945
  totalMatched: number;
797
946
  page: number;
@@ -807,6 +956,8 @@ export interface SearchResponse {
807
956
  mainProperties?: Record<string, Record<string, string>>;
808
957
  /** Free-form memories per record (when includeMemories is true). */
809
958
  memories?: Record<string, MemoryItem[]>;
959
+ /** Compatibility flattened result list derived client-side when possible. */
960
+ results?: SearchResultItem[];
810
961
  }
811
962
  /** @deprecated Use SearchResponse instead. */
812
963
  export type ExportResponse = SearchResponse;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@personize/sdk",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "Official Personize SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",