@personize/sdk 0.7.1 → 0.7.3

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/dist/client.d.ts CHANGED
@@ -27,6 +27,8 @@ export declare class Personize {
27
27
  private normalizeSearchResponse;
28
28
  private normalizeRecallResponse;
29
29
  private isBatchRecordProperty;
30
+ private hasRecordIdentity;
31
+ private buildContentValueWithMetadata;
30
32
  private memorizeBatchFromRecords;
31
33
  /**
32
34
  * GET /api/v1/test — Verify API key is valid. Returns request metadata and resolved identity.
@@ -242,6 +244,32 @@ export declare class Personize {
242
244
  */
243
245
  segment: (data: SegmentOptions) => Promise<ApiResponse<SegmentResponse>>;
244
246
  };
247
+ smartRecallUnified: (data: import("./types").SmartRecallUnifiedOptions) => Promise<import("./types").ApiResponse<import("./types").SmartRecallUnifiedResponse>>;
248
+ rag: {
249
+ configure: (data: import("./types").ExternalRAGConfigOptions) => Promise<import("./types").ApiResponse<{
250
+ configured: boolean;
251
+ }>>;
252
+ search: (data: import("./types").ExternalRAGSearchOptions) => Promise<import("./types").ApiResponse<{
253
+ results: import("./types").ExternalRAGSearchResult[];
254
+ }>>;
255
+ test: () => Promise<import("./types").ApiResponse<{
256
+ healthy: boolean;
257
+ latencyMs: number;
258
+ }>>;
259
+ };
260
+ multimodal: {
261
+ memorize: (data: import("./types").MultimodalMemorizeOptions) => Promise<import("./types").ApiResponse<{
262
+ stored: boolean;
263
+ }>>;
264
+ search: (data: import("./types").MultimodalSearchOptions) => Promise<import("./types").ApiResponse<{
265
+ results: import("./types").MultimodalSearchResult[];
266
+ }>>;
267
+ status: () => Promise<import("./types").ApiResponse<{
268
+ enabled: boolean;
269
+ provider?: string;
270
+ model?: string;
271
+ }>>;
272
+ };
245
273
  evaluate: {
246
274
  /**
247
275
  * POST /api/v1/evaluate/memorization-accuracy — Run memorization accuracy evaluation.
package/dist/client.js CHANGED
@@ -475,6 +475,41 @@ class Personize {
475
475
  return response.data;
476
476
  },
477
477
  };
478
+ // ============ SmartRecall Unified ============
479
+ this.smartRecallUnified = async (data) => {
480
+ const response = await this.client.post('/api/v1/smart-recall-unified', data);
481
+ return response.data;
482
+ };
483
+ // ============ External RAG ============
484
+ this.rag = {
485
+ configure: async (data) => {
486
+ const response = await this.client.post('/api/v1/external-rag/config', data);
487
+ return response.data;
488
+ },
489
+ search: async (data) => {
490
+ const response = await this.client.post('/api/v1/external-rag/search', data);
491
+ return response.data;
492
+ },
493
+ test: async () => {
494
+ const response = await this.client.post('/api/v1/external-rag/test', {});
495
+ return response.data;
496
+ },
497
+ };
498
+ // ============ Multimodal ============
499
+ this.multimodal = {
500
+ memorize: async (data) => {
501
+ const response = await this.client.post('/api/v1/multimodal/memorize', data);
502
+ return response.data;
503
+ },
504
+ search: async (data) => {
505
+ const response = await this.client.post('/api/v1/multimodal/search', data);
506
+ return response.data;
507
+ },
508
+ status: async () => {
509
+ const response = await this.client.get('/api/v1/multimodal/status');
510
+ return response.data;
511
+ },
512
+ };
478
513
  this.evaluate = {
479
514
  /**
480
515
  * POST /api/v1/evaluate/memorization-accuracy — Run memorization accuracy evaluation.
@@ -895,21 +930,46 @@ class Personize {
895
930
  isBatchRecordProperty(value) {
896
931
  return typeof value === 'object' && value !== null && 'value' in value;
897
932
  }
933
+ hasRecordIdentity(record) {
934
+ return Boolean(record.email
935
+ || record.website_url || record.websiteUrl
936
+ || record.record_id || record.recordId
937
+ || record.customKeyValue);
938
+ }
939
+ buildContentValueWithMetadata(record) {
940
+ const content = String(record.content);
941
+ const metaParts = [];
942
+ if (record.speaker)
943
+ metaParts.push(`Speaker: ${record.speaker}`);
944
+ if (record.timestamp)
945
+ metaParts.push(`Date: ${record.timestamp}`);
946
+ if (!metaParts.length)
947
+ return content;
948
+ return `[${metaParts.join(' | ')}] ${content}`;
949
+ }
898
950
  async memorizeBatchFromRecords(data) {
899
951
  const records = data.records || [];
900
952
  if (!records.length) {
901
953
  return { success: true, data: { memorized: 0 } };
902
954
  }
903
- const contentRecords = records.filter((record) => record.content);
904
- for (const record of contentRecords) {
955
+ const batchRecords = [];
956
+ const fallbackRecords = [];
957
+ for (const record of records) {
958
+ const hasContent = Boolean(record.content && String(record.content).trim());
959
+ const hasProperties = Boolean(record.properties && Object.keys(record.properties).length > 0);
960
+ if (!hasContent && !hasProperties)
961
+ continue;
962
+ if (this.hasRecordIdentity(record)) {
963
+ batchRecords.push(record);
964
+ }
965
+ else if (hasContent) {
966
+ fallbackRecords.push(record);
967
+ }
968
+ }
969
+ const fallbackPromises = fallbackRecords.map(async (record) => {
905
970
  const normalizedMemorize = await this.normalizeMemorizeOptions({
906
971
  content: String(record.content),
907
- email: record.email,
908
- website_url: record.website_url || record.websiteUrl,
909
- record_id: record.record_id || record.recordId,
910
972
  type: record.type,
911
- customKeyName: record.customKeyName,
912
- customKeyValue: record.customKeyValue,
913
973
  tags: record.tags,
914
974
  enhanced: record.enhanced ?? data.enhanced,
915
975
  timestamp: record.timestamp,
@@ -917,20 +977,23 @@ class Personize {
917
977
  collectionNames: record.collectionName ? [record.collectionName] : undefined,
918
978
  collectionIds: record.collectionId ? [record.collectionId] : undefined,
919
979
  });
920
- await this.memory.memorize(normalizedMemorize);
921
- }
922
- const structuredRecords = records.filter((record) => record.properties && Object.keys(record.properties).length > 0);
923
- if (!structuredRecords.length) {
924
- return { success: true, data: { memorized: contentRecords.length } };
980
+ return this.memory.memorize(normalizedMemorize);
981
+ });
982
+ if (!batchRecords.length) {
983
+ if (fallbackPromises.length) {
984
+ await Promise.all(fallbackPromises);
985
+ }
986
+ return { success: true, data: { memorized: fallbackRecords.length } };
925
987
  }
926
- const first = structuredRecords[0];
988
+ const first = batchRecords[0];
927
989
  const entityType = first.type || this.inferEntityTypeFromKeys({
928
990
  email: first.email,
929
991
  website_url: first.website_url,
930
992
  websiteUrl: first.websiteUrl,
931
993
  }) || 'Record';
932
994
  const mappingProperties = {};
933
- const rows = structuredRecords.map((record) => {
995
+ const rows = [];
996
+ for (const record of batchRecords) {
934
997
  const row = {};
935
998
  if (record.email)
936
999
  row.email = record.email;
@@ -940,6 +1003,17 @@ class Personize {
940
1003
  row.record_id = record.record_id || record.recordId;
941
1004
  if (record.customKeyValue)
942
1005
  row.custom_key = record.customKeyValue;
1006
+ if (record.content && String(record.content).trim()) {
1007
+ row._content = this.buildContentValueWithMetadata(record);
1008
+ if (!mappingProperties._content) {
1009
+ mappingProperties._content = {
1010
+ sourceField: '_content',
1011
+ collectionId: '',
1012
+ collectionName: '',
1013
+ extractMemories: true,
1014
+ };
1015
+ }
1016
+ }
943
1017
  for (const [propertyName, rawProperty] of Object.entries(record.properties || {})) {
944
1018
  const property = this.isBatchRecordProperty(rawProperty)
945
1019
  ? rawProperty
@@ -954,11 +1028,11 @@ class Personize {
954
1028
  };
955
1029
  }
956
1030
  }
957
- return row;
958
- });
959
- const unresolvedNames = Array.from(new Set(Object.values(mappingProperties)
960
- .filter((property) => !property.collectionId && property.collectionName)
961
- .map((property) => property.collectionName)));
1031
+ rows.push(row);
1032
+ }
1033
+ const unresolvedNames = Array.from(new Set(Object.entries(mappingProperties)
1034
+ .filter(([name, property]) => name !== '_content' && !property.collectionId && property.collectionName)
1035
+ .map(([, property]) => property.collectionName)));
962
1036
  const resolvedMap = new Map();
963
1037
  if (unresolvedNames.length) {
964
1038
  const collections = await this.listAllCollections();
@@ -968,7 +1042,9 @@ class Personize {
968
1042
  }
969
1043
  }
970
1044
  }
971
- for (const property of Object.values(mappingProperties)) {
1045
+ for (const [name, property] of Object.entries(mappingProperties)) {
1046
+ if (name === '_content')
1047
+ continue;
972
1048
  if (!property.collectionId && property.collectionName) {
973
1049
  property.collectionId = resolvedMap.get(property.collectionName.toLowerCase()) || '';
974
1050
  }
@@ -977,7 +1053,7 @@ class Personize {
977
1053
  }
978
1054
  }
979
1055
  const { organizationId, userId } = await this.resolveIdentity();
980
- const response = await this.client.post('/api/v1/batch-memorize', {
1056
+ const batchPromise = this.client.post('/api/v1/batch-memorize', {
981
1057
  source: data.source || 'SDK records shorthand',
982
1058
  tier: data.tier,
983
1059
  dryRun: data.dryRun,
@@ -986,6 +1062,7 @@ class Personize {
986
1062
  entityType,
987
1063
  email: rows.some((row) => row.email) ? 'email' : undefined,
988
1064
  website: rows.some((row) => row.website) ? 'website' : undefined,
1065
+ recordId: rows.some((row) => row.record_id) ? 'record_id' : undefined,
989
1066
  customKeyName: first.customKeyName,
990
1067
  customKey: rows.some((row) => row.custom_key) ? 'custom_key' : undefined,
991
1068
  properties: mappingProperties,
@@ -994,7 +1071,11 @@ class Personize {
994
1071
  orgId: organizationId,
995
1072
  userId,
996
1073
  });
997
- return response.data;
1074
+ const [batchResponse] = await Promise.all([
1075
+ batchPromise,
1076
+ ...fallbackPromises,
1077
+ ]);
1078
+ return batchResponse.data;
998
1079
  }
999
1080
  /**
1000
1081
  * GET /api/v1/test — Verify API key is valid. Returns request metadata and resolved identity.
package/dist/types.d.ts CHANGED
@@ -851,6 +851,8 @@ export interface BatchMemorizeMapping {
851
851
  email?: string;
852
852
  /** Source field name that contains the website URL (e.g. 'company_website_url') */
853
853
  website?: string;
854
+ /** Source field name that contains a pre-resolved record ID (e.g. 'record_id') */
855
+ recordId?: string;
854
856
  /**
855
857
  * Custom key name — the identifier name for custom entity types (e.g. 'studentNumber', 'linkedinUrl').
856
858
  * Use with `customKey` to specify which source field holds the identifier value.
@@ -981,6 +983,10 @@ export interface SmartDigestOptions {
981
983
  deviceId?: string;
982
984
  /** Content ID for entity scoping. */
983
985
  contentId?: string;
986
+ /** Custom key name for custom entity types (e.g. 'linkedin_url', 'studentNumber'). */
987
+ customKeyName?: string;
988
+ /** Custom key value. Used with customKeyName to scope to a custom-keyed record. */
989
+ customKeyValue?: string;
984
990
  }
985
991
  export interface SmartDigestResponse {
986
992
  success: boolean;
@@ -1058,6 +1064,27 @@ export interface MemoryItem {
1058
1064
  score?: number;
1059
1065
  metadata?: Record<string, PropertyValue>;
1060
1066
  }
1067
+ /** CRM identifier keys for a record, returned in search responses. */
1068
+ export interface RecordCrmKeys {
1069
+ type?: string;
1070
+ email?: string;
1071
+ websiteUrl?: string;
1072
+ phoneNumber?: string;
1073
+ postalCode?: string;
1074
+ deviceId?: string;
1075
+ contentId?: string;
1076
+ customKeyName?: string;
1077
+ customKeyValue?: string;
1078
+ }
1079
+ /** AI extraction metadata aggregated per record, returned in search responses. */
1080
+ export interface RecordIndexMeta {
1081
+ entities?: string[];
1082
+ keywords?: string[];
1083
+ persons?: string[];
1084
+ topics?: string[];
1085
+ locations?: string[];
1086
+ sources?: string[];
1087
+ }
1061
1088
  export interface SearchResultItem {
1062
1089
  recordId?: string;
1063
1090
  mainProperties?: Record<string, string>;
@@ -1099,6 +1126,10 @@ export interface SearchResponse extends Array<SearchResultItem> {
1099
1126
  memories?: Record<string, MemoryItem[]>;
1100
1127
  /** Compatibility flattened result list derived client-side when possible. */
1101
1128
  results?: SearchResultItem[];
1129
+ /** CRM keys per record (email, phone, website, etc.). */
1130
+ crmKeys?: Record<string, RecordCrmKeys>;
1131
+ /** AI extraction metadata per record (entities, keywords, persons, etc.). */
1132
+ indexMeta?: Record<string, RecordIndexMeta>;
1102
1133
  }
1103
1134
  /** @deprecated Use SearchResponse instead. */
1104
1135
  export type ExportResponse = SearchResponse;
@@ -1727,3 +1758,104 @@ export interface SegmentResponse {
1727
1758
  credits: number;
1728
1759
  };
1729
1760
  }
1761
+ /** SmartRecall Unified: 1 endpoint replaces 10 for LLMs/agents. Natural language in, structured intelligence out. */
1762
+ export interface SmartRecallUnifiedOptions {
1763
+ /** Natural language query describing what you need from memory. Be specific. */
1764
+ message: string;
1765
+ /** Scope to specific records by identifier. Omit for org-wide queries. */
1766
+ identifiers?: {
1767
+ emails?: string[];
1768
+ websites?: string[];
1769
+ recordIds?: string[];
1770
+ type?: string;
1771
+ };
1772
+ /** Control response depth. Auto-detected from query if omitted. */
1773
+ responseDetail?: 'ids' | 'labels' | 'summary' | 'context' | 'full';
1774
+ /** Max tokens for the response. Default: 4000. */
1775
+ tokenBudget?: number;
1776
+ /** Classification mode. "fast" (~50ms rules), "deep" (~500ms LLM), "auto" (default). */
1777
+ mode?: 'fast' | 'deep' | 'auto';
1778
+ /** Include results from external RAG source (if configured). Default: true. */
1779
+ includeExternalRag?: boolean;
1780
+ /** Include multimodal search results (if enabled). Default: false. */
1781
+ includeMultimodal?: boolean;
1782
+ }
1783
+ export interface SmartRecallUnifiedRecord {
1784
+ recordId: string;
1785
+ type?: string;
1786
+ email?: string;
1787
+ websiteUrl?: string;
1788
+ label?: string;
1789
+ summary?: Record<string, unknown>;
1790
+ context?: string;
1791
+ memories?: {
1792
+ text: string;
1793
+ topic?: string;
1794
+ score?: number;
1795
+ source?: string;
1796
+ }[];
1797
+ properties?: Record<string, unknown>;
1798
+ score?: number;
1799
+ relevanceTier?: 'direct' | 'partial' | 'might';
1800
+ sources?: string[];
1801
+ }
1802
+ export interface SmartRecallUnifiedResponse {
1803
+ success: boolean;
1804
+ answer?: string;
1805
+ plan: {
1806
+ classifiedAs: string[];
1807
+ steps: string[];
1808
+ mode: 'fast' | 'deep';
1809
+ confidence: number;
1810
+ };
1811
+ records: SmartRecallUnifiedRecord[];
1812
+ meta: {
1813
+ totalMatched: number;
1814
+ returned: number;
1815
+ enrichmentDepth: string;
1816
+ tokensUsed: number;
1817
+ creditsCharged: number;
1818
+ latencyMs: number;
1819
+ sources: string[];
1820
+ };
1821
+ }
1822
+ export interface ExternalRAGConfigOptions {
1823
+ url: string;
1824
+ apiKey: string;
1825
+ timeout?: number;
1826
+ maxResults?: number;
1827
+ }
1828
+ export interface ExternalRAGSearchOptions {
1829
+ query: string;
1830
+ limit?: number;
1831
+ context?: {
1832
+ recordId?: string;
1833
+ type?: string;
1834
+ };
1835
+ }
1836
+ export interface ExternalRAGSearchResult {
1837
+ text: string;
1838
+ score: number;
1839
+ source: string;
1840
+ url?: string;
1841
+ metadata?: Record<string, unknown>;
1842
+ }
1843
+ export interface MultimodalMemorizeOptions {
1844
+ recordId: string;
1845
+ type: string;
1846
+ attachment: string;
1847
+ mimeType: string;
1848
+ content?: string;
1849
+ }
1850
+ export interface MultimodalSearchOptions {
1851
+ image: string;
1852
+ mimeType: string;
1853
+ limit?: number;
1854
+ }
1855
+ export interface MultimodalSearchResult {
1856
+ recordId: string;
1857
+ score: number;
1858
+ text?: string;
1859
+ sourceUrl?: string;
1860
+ mimeType?: string;
1861
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@personize/sdk",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "Official Personize SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",