@personize/sdk 0.6.1 → 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
@@ -134,7 +134,7 @@ const byok = await client.ai.prompt({
134
134
  model: 'anthropic/claude-sonnet-4-20250514',
135
135
  provider: 'openrouter',
136
136
  });
137
- // BYOK billing: time-based (10 credits base + 10/extra minute) instead of per-token
137
+ // BYOK billing: flat 5 credits/call no per-token charge, you pay your provider directly
138
138
  // Without BYOK, model/provider are rejected — use tier to control quality level
139
139
 
140
140
  // Multi-step instructions with evaluation
@@ -216,6 +216,32 @@ const fast = await client.memory.smartRecall({
216
216
  // min_results: 10 (default in fast_mode — always returns top N even below score threshold)
217
217
  });
218
218
 
219
+ // Custom keys — bring your own identifier for any entity type
220
+ // Use customKeyName/customKeyValue when email or websiteUrl don't apply.
221
+ // The recordId is generated deterministically from orgId + type + key — same key always resolves to the same record.
222
+ await client.memory.memorize({
223
+ content: 'Student enrolled in Advanced AI course. GPA 3.8, Dean\'s List.',
224
+ type: 'Student',
225
+ customKeyName: 'studentNumber',
226
+ customKeyValue: 'S-2024-1234',
227
+ enhanced: true,
228
+ });
229
+
230
+ // More examples: LinkedIn profiles, web pages, code files, products...
231
+ await client.memory.memorize({ content: '...', type: 'Person', customKeyName: 'linkedinUrl', customKeyValue: 'https://linkedin.com/in/johndoe' });
232
+ await client.memory.memorize({ content: '...', type: 'Webpage', customKeyName: 'pageUrl', customKeyValue: 'https://docs.example.com/api/auth' });
233
+ await client.memory.memorize({ content: '...', type: 'File', customKeyName: 'filePath', customKeyValue: 'src/auth/oauth.ts' });
234
+ await client.memory.memorize({ content: '...', type: 'Product', customKeyName: 'sku', customKeyValue: 'PRD-X100-BLK' });
235
+
236
+ // Recall by the same custom key — no need to know the recordId
237
+ const student = await client.memory.smartRecall({
238
+ query: 'What courses is this student enrolled in?',
239
+ type: 'Student',
240
+ customKeyName: 'studentNumber',
241
+ customKeyValue: 'S-2024-1234',
242
+ fast_mode: true,
243
+ });
244
+
219
245
  // Direct recall — DynamoDB lookup: properties + freeform memories (no AI, type required)
220
246
  const direct = await client.memory.recall({
221
247
  query: 'What do we know about Acme?',
@@ -225,7 +251,15 @@ const direct = await client.memory.recall({
225
251
  // direct.data.memories — structured properties from Snapshot
226
252
  // direct.data.freeformMemories — AI-extracted memories from Freeform table
227
253
 
228
- // Search/filter records by property conditions
254
+ // Direct recall by custom key
255
+ const student = await client.memory.recall({
256
+ query: 'Academic record',
257
+ type: 'Student',
258
+ customKeyName: 'studentNumber',
259
+ customKeyValue: 'S-2024-1234',
260
+ });
261
+
262
+ // Search/filter records by property conditions — works with any type value
229
263
  const found = await client.memory.search({
230
264
  groups: [{
231
265
  conditions: [{ property: 'company-name', operator: 'equals', value: 'Acme Corp' }],
@@ -234,6 +268,64 @@ const found = await client.memory.search({
234
268
  pageSize: 50,
235
269
  });
236
270
 
271
+ // Search across a custom entity type
272
+ const deansList = await client.memory.search({
273
+ type: 'Student',
274
+ returnRecords: true,
275
+ groups: [{
276
+ conditions: [{ property: 'gpa', operator: 'GTE', value: 3.5 }],
277
+ }],
278
+ });
279
+
280
+ // Access property values: records[recordId][propertyName].value (plain string)
281
+ for (const [recordId, props] of Object.entries(found.data?.records ?? {})) {
282
+ const email = props['email']?.value; // plain string — whatever was stored
283
+ const company = props['company-name']?.value;
284
+ console.log(`${recordId}: ${email} at ${company}`);
285
+ }
286
+ // Note: 'email' and 'company-name' must match the property names in your collection definition
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
+
237
329
  // Batch sync — unified call with per-property extractMemories control
238
330
  // IMPORTANT: Set extractMemories: true on rich text fields (notes, transcripts, descriptions)
239
331
  // to enable AI extraction and semantic search. Without it, only structured storage occurs.
@@ -241,6 +333,9 @@ await client.memory.memorizeBatch({
241
333
  source: 'Hubspot',
242
334
  mapping: {
243
335
  entityType: 'contact',
336
+ // email: 'email' means "use the 'email' field from each row as the contact identifier"
337
+ // The value must match the key name in your rows array (e.g., row.email)
338
+ // Use websiteUrl instead for Company records, or recordId for direct ID matching
244
339
  email: 'email',
245
340
  properties: {
246
341
  email: { sourceField: 'email', collectionId: 'col_std', collectionName: 'Standard', extractMemories: false },
@@ -253,6 +348,25 @@ await client.memory.memorizeBatch({
253
348
  ],
254
349
  });
255
350
 
351
+ // Batch sync with custom keys — for non-Contact/Company entity types
352
+ await client.memory.memorizeBatch({
353
+ source: 'University DB',
354
+ mapping: {
355
+ entityType: 'Student',
356
+ customKeyName: 'studentNumber', // the identifier name
357
+ customKey: 'student_id', // source field in rows holding the value
358
+ properties: {
359
+ full_name: { sourceField: 'name', collectionId: 'col_std', collectionName: 'Standard', extractMemories: false },
360
+ gpa: { sourceField: 'gpa', collectionId: 'col_std', collectionName: 'Standard', extractMemories: false },
361
+ notes: { sourceField: 'notes', collectionId: 'col_gen', collectionName: 'Generated', extractMemories: true },
362
+ },
363
+ },
364
+ rows: [
365
+ { student_id: 'S-2024-1234', name: 'Alice Chen', gpa: '3.8', notes: 'Dean\'s List, AI research focus' },
366
+ { student_id: 'S-2024-5678', name: 'Bob Park', gpa: '3.5', notes: 'Full-stack internship at Stripe' },
367
+ ],
368
+ });
369
+
256
370
  // Smart memory digest — compiled context for an entity
257
371
  const digest = await client.memory.smartDigest({
258
372
  email: 'john@acme.com',
@@ -325,27 +439,29 @@ console.log(evaluation.data.summary.propertiesOptimized);
325
439
 
326
440
  | Tier | Input Credits/1K tokens | Output Credits/1K tokens | Best For |
327
441
  | :--- | :--- | :--- | :--- |
328
- | `basic` | 0.2 | 0.4 | High-volume, simple tasks |
329
- | `pro` | 0.5 | 1.0 | Balanced quality & cost (default) |
330
- | `ultra` | 1.0 | 2.5 | Complex reasoning, highest quality |
442
+ | `basic` | 1.0 | 2.0 | High-volume, simple tasks |
443
+ | `pro` | 1.0 | 3.0 | Balanced quality & cost (default) |
444
+ | `ultra` | 1.0 | 5.0 | Complex reasoning, highest quality |
331
445
 
332
446
  ### Memorize Tiers
333
447
 
334
448
  | Tier | Credits/1K tokens | Best For |
335
449
  | :--- | :--- | :--- |
336
- | `basic` | 1.0 | Bulk imports, simple data |
337
- | `pro` | 2.5 | General use (default) |
338
- | `pro_fast` | 3.5 | Pro quality, lower latency |
339
- | `ultra` | 7.0 | Maximum extraction quality |
450
+ | `basic` | 1 | Bulk imports, simple data |
451
+ | `pro` | 3 | General use (default) |
452
+ | `pro_fast` | 5 | Pro quality, lower latency |
453
+ | `ultra` | 12 | Maximum extraction quality |
340
454
 
341
455
  ### Retrieval (Recall & Smart Guidelines)
342
456
 
343
457
  | Operation | Mode | Credits/Call |
344
458
  | :--- | :--- | :--- |
345
- | Smart Recall | `fast_mode: true` | 0.1 |
346
- | Smart Recall | `fast_mode: false` (deep) | 0.2 |
347
- | Smart Guidelines | `mode: 'fast'` | 0.1 |
348
- | Smart Guidelines | `mode: 'deep'` | 0.5 |
459
+ | Smart Recall | `fast_mode: true` | 1 |
460
+ | Smart Recall | `fast_mode: false` (deep) | 1 |
461
+ | Smart Guidelines | `mode: 'fast'` | 1 |
462
+ | Smart Guidelines | `mode: 'deep'` | 1 |
463
+
464
+ All read operations (recall, smart recall, smart guidelines, smart context) charge a flat **1 credit per call** regardless of mode. Mode choice affects latency and depth, not cost.
349
465
 
350
466
  1 credit = $0.01.
351
467
 
@@ -353,7 +469,7 @@ console.log(evaluation.data.summary.propertiesOptimized);
353
469
 
354
470
  ### BYOK (Bring Your Own Key)
355
471
 
356
- Pro and Enterprise plans can pass their own API key. Billing switches to time-based: **10 credits base + 10 credits per additional minute**.
472
+ Pro and Enterprise plans can pass their own API key. Billing switches to a flat **5 credits per call** (no per-token charge — you pay your provider directly).
357
473
 
358
474
  When using BYOK, you **must** provide both `model` and `provider`. Without BYOK, `model` and `provider` are rejected — use `tier` to control quality level.
359
475
 
@@ -378,7 +494,7 @@ await client.ai.prompt({
378
494
  - `openrouterApiKey` without `model`/`provider` → `400 model and provider required`
379
495
  - BYOK on a plan that doesn't allow it → `403 byok_not_allowed`
380
496
 
381
- Response metadata includes `byok: true` and `creditsCharged` reflecting time-based billing.
497
+ Response metadata includes `byok: true` and `creditsCharged` reflecting the flat 5-credit charge.
382
498
 
383
499
  ## Best Practices: Query Crafting for smartRecall
384
500
 
@@ -427,7 +543,23 @@ const client = new Personize({
427
543
  });
428
544
  ```
429
545
 
430
- ## 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
431
563
 
432
564
  **New in 0.6.0:**
433
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).
@@ -551,12 +594,28 @@ export interface MemorizeOptions {
551
594
  email?: string;
552
595
  /** Website URL for CRM linking. */
553
596
  website_url?: string;
597
+ /** Entity type (e.g. 'Contact', 'Company', 'Student', 'Webpage'). */
598
+ type?: string;
599
+ /**
600
+ * Custom key name — for entity types with domain-specific unique IDs.
601
+ * Examples: 'studentNumber', 'linkedinUrl', 'employeeId', 'pageUrl', 'productSku'.
602
+ * Used with customKeyValue to identify the record when email/websiteUrl don't apply.
603
+ */
604
+ customKeyName?: string;
605
+ /** Custom key value — the unique identifier value (e.g. 'S12345', 'https://linkedin.com/in/johndoe'). */
606
+ customKeyValue?: string;
554
607
  /** Enable enhanced dual extraction (structured + free-form). */
555
608
  enhanced?: boolean;
609
+ /** Compatibility shorthand for structured property writes. */
610
+ properties?: Record<string, unknown | BatchMemorizeRecordProperty>;
556
611
  /** Tags for property selection. */
557
612
  tags?: string[];
558
613
  /** Limit extraction to specific collections. */
559
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[];
560
619
  /** Max properties to select for extraction. */
561
620
  max_properties?: number;
562
621
  /** If true, extract without persisting (dry run). */
@@ -571,6 +630,8 @@ export type MemorizeProOptions = MemorizeOptions;
571
630
  export interface SmartRecallOptions {
572
631
  /** Natural-language query. */
573
632
  query: string;
633
+ /** Compatibility alias for query. */
634
+ message?: string;
574
635
  /** Max results to return (default: 10). */
575
636
  limit?: number;
576
637
  /** Minimum similarity score threshold. */
@@ -587,10 +648,16 @@ export interface SmartRecallOptions {
587
648
  websiteUrl?: string;
588
649
  /** Entity type filter (e.g. 'Contact', 'Company'). */
589
650
  type?: string;
651
+ /** Custom key name — for entity types with domain-specific unique IDs. */
652
+ customKeyName?: string;
653
+ /** Custom key value — the unique identifier value. */
654
+ customKeyValue?: string;
590
655
  /** Scope results to specific collections by ID. */
591
656
  collectionIds?: string[];
592
657
  /** Scope results to specific collections by name (resolved server-side, case-insensitive). */
593
658
  collectionNames?: string[];
659
+ /** Compatibility alias for a single collection name. */
660
+ collectionName?: string;
594
661
  /** Return schema-enforced property values separately from free-form memories. */
595
662
  include_property_values?: boolean;
596
663
  /** Enable reflection loop to improve recall coverage (default: true). */
@@ -622,9 +689,13 @@ export interface SmartRecallOptions {
622
689
  export type RecallProOptions = SmartRecallOptions;
623
690
  export interface RecallOptions {
624
691
  /** Natural-language query. */
625
- query: string;
626
- /** Entity type (e.g. 'Contact', 'Company'). Required by the /recall endpoint. */
627
- 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;
628
699
  /** CRM record ID for entity scoping. */
629
700
  record_id?: string;
630
701
  /** CRM record ID (camelCase alias). */
@@ -635,8 +706,39 @@ export interface RecallOptions {
635
706
  website_url?: string;
636
707
  /** Website URL (camelCase alias). */
637
708
  websiteUrl?: string;
709
+ /** Custom key name — for entity types with domain-specific unique IDs. */
710
+ customKeyName?: string;
711
+ /** Custom key value — the unique identifier value. */
712
+ customKeyValue?: string;
638
713
  /** Additional filters. */
639
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;
640
742
  }
641
743
  export interface BatchMemorizePropertyMapping {
642
744
  /** Source field name in the row data */
@@ -649,12 +751,19 @@ export interface BatchMemorizePropertyMapping {
649
751
  extractMemories?: boolean;
650
752
  }
651
753
  export interface BatchMemorizeMapping {
652
- /** Entity type (e.g. 'contact', 'company') */
754
+ /** Entity type (e.g. 'contact', 'company', 'Student', 'Webpage') */
653
755
  entityType: string;
654
756
  /** Source field name that contains the email (e.g. 'email') */
655
757
  email?: string;
656
758
  /** Source field name that contains the website URL (e.g. 'company_website_url') */
657
759
  website?: string;
760
+ /**
761
+ * Custom key name — the identifier name for custom entity types (e.g. 'studentNumber', 'linkedinUrl').
762
+ * Use with `customKey` to specify which source field holds the identifier value.
763
+ */
764
+ customKeyName?: string;
765
+ /** Source field name that contains the custom key value (e.g. 'student_id', 'linkedin_url') */
766
+ customKey?: string;
658
767
  /** Run name for tracking (e.g. 'hubspot Sync (contact) - <uuid>') */
659
768
  runName?: string;
660
769
  /** Property mappings: target property name → mapping config */
@@ -662,17 +771,45 @@ export interface BatchMemorizeMapping {
662
771
  }
663
772
  export interface BatchMemorizeOptions {
664
773
  /** Source system label (e.g. 'Hubspot', 'Salesforce') */
665
- source: string;
774
+ source?: string;
666
775
  /** Memorize tier: 'basic' | 'pro' | 'pro_fast' | 'ultra'. Default: 'pro'. */
667
776
  tier?: 'basic' | 'pro' | 'pro_fast' | 'ultra';
668
777
  /** Mapping configuration for the sync */
669
- mapping: BatchMemorizeMapping;
778
+ mapping?: BatchMemorizeMapping;
670
779
  /** Array of source data rows (key-value objects matching sourceField names) */
671
- rows: Record<string, unknown>[];
780
+ rows?: Record<string, unknown>[];
672
781
  /** If true, validate without writing (default: false) */
673
782
  dryRun?: boolean;
674
783
  /** Number of rows to process per chunk (default: 1) */
675
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;
676
813
  }
677
814
  export interface SmartDigestOptions {
678
815
  /** CRM record ID */
@@ -733,6 +870,8 @@ export interface SearchFilterGroup {
733
870
  conditions: SearchFilterCondition[];
734
871
  }
735
872
  export interface SearchOptions {
873
+ /** Compatibility shorthand for semantic search; routed client-side to smartRecall when groups are omitted. */
874
+ query?: string;
736
875
  /** Filter groups with conditions. To list all records, send one group with empty conditions. */
737
876
  groups?: SearchFilterGroup[];
738
877
  /** Entity type (e.g. 'Contact', 'Company'). */
@@ -743,12 +882,22 @@ export interface SearchOptions {
743
882
  websiteUrl?: string;
744
883
  /** Scope to a specific record ID. */
745
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;
746
889
  /** Scope to specific collections. */
747
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[];
748
895
  /** Page number (1-based, default: 1). */
749
896
  page?: number;
750
897
  /** Results per page (max 200, default: 50). */
751
898
  pageSize?: number;
899
+ /** Compatibility alias for pageSize. */
900
+ limit?: number;
752
901
  /** Return only totalMatched count. */
753
902
  countOnly?: boolean;
754
903
  /** Include property values per record. */
@@ -757,6 +906,8 @@ export interface SearchOptions {
757
906
  includeMemories?: boolean;
758
907
  /** Data source: 'lancedb' or 'snapshot' (default: 'lancedb'). */
759
908
  dataSource?: 'lancedb' | 'snapshot';
909
+ /** Compatibility shorthand filters; converted client-side to groups where possible. */
910
+ filters?: Record<string, unknown>;
760
911
  }
761
912
  /** @deprecated Use SearchOptions instead. */
762
913
  export type ExportOptions = SearchOptions;
@@ -766,7 +917,30 @@ export interface MemoryItem {
766
917
  score?: number;
767
918
  metadata?: Record<string, PropertyValue>;
768
919
  }
769
- 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> {
770
944
  recordIds: string[];
771
945
  totalMatched: number;
772
946
  page: number;
@@ -782,6 +956,8 @@ export interface SearchResponse {
782
956
  mainProperties?: Record<string, Record<string, string>>;
783
957
  /** Free-form memories per record (when includeMemories is true). */
784
958
  memories?: Record<string, MemoryItem[]>;
959
+ /** Compatibility flattened result list derived client-side when possible. */
960
+ results?: SearchResultItem[];
785
961
  }
786
962
  /** @deprecated Use SearchResponse instead. */
787
963
  export type ExportResponse = SearchResponse;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@personize/sdk",
3
- "version": "0.6.1",
3
+ "version": "0.6.4",
4
4
  "description": "Official Personize SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",