@personize/sdk 0.5.3 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -110,10 +110,32 @@ console.log(ctx.data.compiledContext);
110
110
  ### Prompt Execution
111
111
 
112
112
  ```typescript
113
- // Simple prompt
113
+ // Simple prompt (defaults to 'pro' tier)
114
114
  const response = await client.ai.prompt({
115
115
  prompt: 'Summarize our Q4 sales strategy',
116
116
  });
117
+ console.log(response.data?.metadata?.creditsCharged); // credits used
118
+
119
+ // With explicit tier
120
+ const fast = await client.ai.prompt({
121
+ prompt: 'Quick summary of today',
122
+ tier: 'basic', // cheapest, fastest
123
+ });
124
+
125
+ const premium = await client.ai.prompt({
126
+ prompt: 'Deep analysis of market trends',
127
+ tier: 'ultra', // highest quality model
128
+ });
129
+
130
+ // BYOK — use your own API key + model + provider (Pro/Enterprise plans only)
131
+ const byok = await client.ai.prompt({
132
+ prompt: 'Generate a report',
133
+ openrouterApiKey: 'sk-or-v1-...', // your OpenRouter key
134
+ model: 'anthropic/claude-sonnet-4-20250514',
135
+ provider: 'openrouter',
136
+ });
137
+ // BYOK billing: flat 5 credits/call — no per-token charge, you pay your provider directly
138
+ // Without BYOK, model/provider are rejected — use tier to control quality level
117
139
 
118
140
  // Multi-step instructions with evaluation
119
141
  const result = await client.ai.prompt({
@@ -130,7 +152,6 @@ const analysis = await client.ai.prompt({
130
152
  attachments: [
131
153
  { name: 'dashboard.png', mimeType: 'image/png', data: base64EncodedImage },
132
154
  ],
133
- model: 'anthropic/claude-sonnet-4-20250514',
134
155
  });
135
156
 
136
157
  // Multimodal — PDF extraction via URL
@@ -168,14 +189,15 @@ console.log(research.data?.evaluation?.finalScore);
168
189
 
169
190
  ```typescript
170
191
  // Memorize content (dual extraction: structured + free-form)
171
- // Tip: prepend identity field hints to ensure demographic properties are captured
172
- await client.memory.memorize({
173
- content: 'Also extract First Name, Company Name, and Job Title if mentioned.\n\nMeeting notes: John prefers email contact. He is VP of Sales at Acme Corp.',
192
+ // Response includes recordId for immediate use in recall/digest calls
193
+ const memorized = await client.memory.memorize({
194
+ content: 'Meeting notes: John prefers email contact. He is VP of Sales at Acme Corp.',
174
195
  speaker: 'Sales Rep',
175
196
  enhanced: true,
176
197
  tags: ['meetings'],
177
198
  email: 'john@example.com',
178
199
  });
200
+ console.log(memorized.data?.recordId); // REC#<hex> — deterministic, use for recall/digest
179
201
 
180
202
  // Smart recall — advanced recall with reflection
181
203
  const results = await client.memory.smartRecall({
@@ -186,11 +208,38 @@ const results = await client.memory.smartRecall({
186
208
  generate_answer: true,
187
209
  });
188
210
 
189
- // Fast recall — low-latency mode (~500ms)
211
+ // Fast recall — low-latency mode (~500ms), guaranteed min 10 results
190
212
  const fast = await client.memory.smartRecall({
191
213
  query: 'contact info for John',
192
214
  email: 'john@example.com',
193
215
  fast_mode: true,
216
+ // min_results: 10 (default in fast_mode — always returns top N even below score threshold)
217
+ });
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,
194
243
  });
195
244
 
196
245
  // Direct recall — DynamoDB lookup: properties + freeform memories (no AI, type required)
@@ -202,7 +251,15 @@ const direct = await client.memory.recall({
202
251
  // direct.data.memories — structured properties from Snapshot
203
252
  // direct.data.freeformMemories — AI-extracted memories from Freeform table
204
253
 
205
- // 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
206
263
  const found = await client.memory.search({
207
264
  groups: [{
208
265
  conditions: [{ property: 'company-name', operator: 'equals', value: 'Acme Corp' }],
@@ -211,6 +268,23 @@ const found = await client.memory.search({
211
268
  pageSize: 50,
212
269
  });
213
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
+
214
288
  // Batch sync — unified call with per-property extractMemories control
215
289
  // IMPORTANT: Set extractMemories: true on rich text fields (notes, transcripts, descriptions)
216
290
  // to enable AI extraction and semantic search. Without it, only structured storage occurs.
@@ -218,6 +292,9 @@ await client.memory.memorizeBatch({
218
292
  source: 'Hubspot',
219
293
  mapping: {
220
294
  entityType: 'contact',
295
+ // email: 'email' means "use the 'email' field from each row as the contact identifier"
296
+ // The value must match the key name in your rows array (e.g., row.email)
297
+ // Use websiteUrl instead for Company records, or recordId for direct ID matching
221
298
  email: 'email',
222
299
  properties: {
223
300
  email: { sourceField: 'email', collectionId: 'col_std', collectionName: 'Standard', extractMemories: false },
@@ -230,6 +307,25 @@ await client.memory.memorizeBatch({
230
307
  ],
231
308
  });
232
309
 
310
+ // Batch sync with custom keys — for non-Contact/Company entity types
311
+ await client.memory.memorizeBatch({
312
+ source: 'University DB',
313
+ mapping: {
314
+ entityType: 'Student',
315
+ customKeyName: 'studentNumber', // the identifier name
316
+ customKey: 'student_id', // source field in rows holding the value
317
+ properties: {
318
+ full_name: { sourceField: 'name', collectionId: 'col_std', collectionName: 'Standard', extractMemories: false },
319
+ gpa: { sourceField: 'gpa', collectionId: 'col_std', collectionName: 'Standard', extractMemories: false },
320
+ notes: { sourceField: 'notes', collectionId: 'col_gen', collectionName: 'Generated', extractMemories: true },
321
+ },
322
+ },
323
+ rows: [
324
+ { student_id: 'S-2024-1234', name: 'Alice Chen', gpa: '3.8', notes: 'Dean\'s List, AI research focus' },
325
+ { student_id: 'S-2024-5678', name: 'Bob Park', gpa: '3.5', notes: 'Full-stack internship at Stripe' },
326
+ ],
327
+ });
328
+
233
329
  // Smart memory digest — compiled context for an entity
234
330
  const digest = await client.memory.smartDigest({
235
331
  email: 'john@acme.com',
@@ -296,6 +392,97 @@ const evaluation = await client.evaluate.memorizationAccuracy({
296
392
  console.log(evaluation.data.summary.propertiesOptimized);
297
393
  ```
298
394
 
395
+ ## Tiers & Pricing
396
+
397
+ ### Generate Tiers (Prompt)
398
+
399
+ | Tier | Input Credits/1K tokens | Output Credits/1K tokens | Best For |
400
+ | :--- | :--- | :--- | :--- |
401
+ | `basic` | 1.0 | 2.0 | High-volume, simple tasks |
402
+ | `pro` | 1.0 | 3.0 | Balanced quality & cost (default) |
403
+ | `ultra` | 1.0 | 5.0 | Complex reasoning, highest quality |
404
+
405
+ ### Memorize Tiers
406
+
407
+ | Tier | Credits/1K tokens | Best For |
408
+ | :--- | :--- | :--- |
409
+ | `basic` | 1 | Bulk imports, simple data |
410
+ | `pro` | 3 | General use (default) |
411
+ | `pro_fast` | 5 | Pro quality, lower latency |
412
+ | `ultra` | 12 | Maximum extraction quality |
413
+
414
+ ### Retrieval (Recall & Smart Guidelines)
415
+
416
+ | Operation | Mode | Credits/Call |
417
+ | :--- | :--- | :--- |
418
+ | Smart Recall | `fast_mode: true` | 1 |
419
+ | Smart Recall | `fast_mode: false` (deep) | 1 |
420
+ | Smart Guidelines | `mode: 'fast'` | 1 |
421
+ | Smart Guidelines | `mode: 'deep'` | 1 |
422
+
423
+ 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.
424
+
425
+ 1 credit = $0.01.
426
+
427
+ ### Direct Providers
428
+
429
+ ### BYOK (Bring Your Own Key)
430
+
431
+ 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).
432
+
433
+ When using BYOK, you **must** provide both `model` and `provider`. Without BYOK, `model` and `provider` are rejected — use `tier` to control quality level.
434
+
435
+ ```typescript
436
+ // BYOK: must specify all three
437
+ await client.ai.prompt({
438
+ prompt: '...',
439
+ openrouterApiKey: 'sk-or-v1-...',
440
+ model: 'anthropic/claude-sonnet-4-20250514',
441
+ provider: 'openrouter',
442
+ });
443
+
444
+ // Without BYOK: use tier (model/provider auto-selected)
445
+ await client.ai.prompt({
446
+ prompt: '...',
447
+ tier: 'pro', // basic, pro (default), ultra
448
+ });
449
+ ```
450
+
451
+ **Error cases:**
452
+ - `model`/`provider` without `openrouterApiKey` → `400 BYOK required`
453
+ - `openrouterApiKey` without `model`/`provider` → `400 model and provider required`
454
+ - BYOK on a plan that doesn't allow it → `403 byok_not_allowed`
455
+
456
+ Response metadata includes `byok: true` and `creditsCharged` reflecting the flat 5-credit charge.
457
+
458
+ ## Best Practices: Query Crafting for smartRecall
459
+
460
+ The `smartRecall` endpoint uses vector similarity search. Query quality directly impacts result relevance. When building AI pipelines that call `smartRecall`, the **AI agent is responsible for crafting embedding-friendly queries**.
461
+
462
+ **Do:**
463
+ - Use specific, descriptive queries that match the language of stored data
464
+ - Include entity names, property names, or domain-specific terms
465
+ - Example: `"John Smith role title company background"` instead of `"Tell me about this contact"`
466
+
467
+ **Don't:**
468
+ - Use vague meta-queries like `"What do we know?"` or `"Tell me everything"`
469
+ - Use task-oriented queries like `"open tasks pending action items"` when only profile data was memorized
470
+
471
+ **Example — AI pipeline pattern:**
472
+ ```typescript
473
+ // BAD: vague query → low similarity scores → few or no results
474
+ const bad = await client.memory.smartRecall({ query: 'Tell me about this contact', email });
475
+
476
+ // GOOD: specific query targeting stored data types
477
+ const good = await client.memory.smartRecall({
478
+ query: `${contactName} role company background interests preferences`,
479
+ email,
480
+ fast_mode: true,
481
+ });
482
+ ```
483
+
484
+ **Guaranteed minimum results:** In `fast_mode`, `smartRecall` guarantees at least 10 results (configurable via `min_results`) even when scores fall below the threshold. This ensures your AI workflow always has context to reason about — it can then decide whether the data is sufficient or not.
485
+
299
486
  ## Configuration
300
487
 
301
488
  | Option | Type | Required | Description |
@@ -315,6 +502,19 @@ const client = new Personize({
315
502
  });
316
503
  ```
317
504
 
505
+ ## Migration from 0.5.x
506
+
507
+ **New in 0.6.0:**
508
+
509
+ | Feature | Details |
510
+ | :--- | :--- |
511
+ | `tier` on `PromptOptions` | Select generate tier: `basic`, `pro` (default), `ultra` |
512
+ | `tier` on `MemorizeOptions` / `BatchMemorizeOptions` | Select memorize tier: `basic`, `pro`, `pro_fast`, `ultra` |
513
+ | `openrouterApiKey` on `PromptOptions` | BYOK — use your own API key (Pro/Enterprise plans). Requires `model` + `provider`. |
514
+ | `model` / `provider` on `PromptOptions` | Custom model/provider selection. **Requires BYOK** (`openrouterApiKey`). Without BYOK, use `tier`. |
515
+ | `creditsCharged` in response metadata | Credits consumed by the request |
516
+ | SmartGuidelines `mode: 'full'` → `mode: 'deep'` | Renamed for consistency. `'full'` still accepted for backward compatibility. |
517
+
318
518
  ## Migration from 0.3.x
319
519
 
320
520
  **Breaking changes in 0.4.0:**
package/dist/types.d.ts CHANGED
@@ -245,8 +245,8 @@ export interface SmartGuidelinesOptions {
245
245
  tags?: string[];
246
246
  excludeTags?: string[];
247
247
  model?: string;
248
- /** Routing mode: "fast" for instant embedding-only (~200ms), "full" for deep LLM routing (~3s), "auto" to let the system decide. Default: "auto". */
249
- mode?: 'fast' | 'full' | 'auto';
248
+ /** Routing mode: "fast" for instant embedding-only (~200ms), "deep" for LLM routing (~3s), "auto" to let the system decide. "full" is accepted as alias for "deep". Default: "auto". */
249
+ mode?: 'fast' | 'deep' | 'full' | 'auto';
250
250
  /** Minimum cosine similarity score (0-1) for fast mode results. Lower values return more results. Default: 0.4 for supplementary, 0.7 for critical. */
251
251
  minScore?: number;
252
252
  /** Session ID for conversation continuity. */
@@ -290,8 +290,10 @@ export interface SmartGuidelinesUsage {
290
290
  export type SmartContextUsage = SmartGuidelinesUsage;
291
291
  export interface SmartGuidelinesResponse {
292
292
  success: boolean;
293
- /** Which routing mode was actually used. */
294
- mode: 'fast' | 'full';
293
+ /** Which routing mode was actually used. "full" may appear for backward compat (equivalent to "deep"). */
294
+ mode: 'fast' | 'deep' | 'full';
295
+ /** Credits charged for this request. */
296
+ creditsCharged?: number;
295
297
  /** LLM analysis of the task. Null in fast mode. */
296
298
  analysis?: SmartGuidelinesAnalysis | null;
297
299
  selection: SmartGuidelinesSelection[];
@@ -389,8 +391,14 @@ export interface PromptOptions {
389
391
  maxSteps?: number;
390
392
  }>;
391
393
  stream?: boolean;
394
+ /** LLM model. Requires BYOK (`openrouterApiKey`). Without BYOK, use `tier` instead — model is auto-selected. */
392
395
  model?: string;
396
+ /** LLM provider: 'openai' | 'anthropic' | 'google' | 'xai' | 'deepseek' | 'openrouter'. Requires BYOK (`openrouterApiKey`). Without BYOK, provider is auto-selected by tier. */
393
397
  provider?: string;
398
+ /** Generate tier: 'basic' (fast/cheap), 'pro' (balanced, default), 'ultra' (highest quality). Determines default model and credit rate. Used when no BYOK key is provided. */
399
+ tier?: 'basic' | 'pro' | 'ultra';
400
+ /** Bring Your Own Key: pass your own OpenRouter (or direct provider) API key. When provided, `model` and `provider` are required. Time-based billing instead of per-token. Requires Pro or Enterprise plan. */
401
+ openrouterApiKey?: string;
394
402
  context?: string;
395
403
  sessionId?: string;
396
404
  /**
@@ -441,6 +449,12 @@ export interface PromptResponse {
441
449
  metadata?: {
442
450
  model: string;
443
451
  provider: string;
452
+ /** Generate tier used for billing. */
453
+ tier?: 'basic' | 'pro' | 'ultra';
454
+ /** Credits charged for this request. 1 credit = $0.01. */
455
+ creditsCharged?: number;
456
+ /** True when BYOK (Bring Your Own Key) billing was applied. */
457
+ byok?: boolean;
444
458
  usage?: {
445
459
  promptTokens: number;
446
460
  completionTokens: number;
@@ -521,6 +535,8 @@ export interface AgentRunOptions {
521
535
  export interface MemorizeOptions {
522
536
  /** Content to memorize. */
523
537
  content: string;
538
+ /** Memorize tier: 'basic' (fast), 'pro' (balanced, default), 'pro_fast' (pro speed), 'ultra' (highest extraction). */
539
+ tier?: 'basic' | 'pro' | 'pro_fast' | 'ultra';
524
540
  /** Speaker/source label. */
525
541
  speaker?: string;
526
542
  /** Timestamp of the content. */
@@ -535,6 +551,16 @@ export interface MemorizeOptions {
535
551
  email?: string;
536
552
  /** Website URL for CRM linking. */
537
553
  website_url?: string;
554
+ /** Entity type (e.g. 'Contact', 'Company', 'Student', 'Webpage'). */
555
+ type?: string;
556
+ /**
557
+ * Custom key name — for entity types with domain-specific unique IDs.
558
+ * Examples: 'studentNumber', 'linkedinUrl', 'employeeId', 'pageUrl', 'productSku'.
559
+ * Used with customKeyValue to identify the record when email/websiteUrl don't apply.
560
+ */
561
+ customKeyName?: string;
562
+ /** Custom key value — the unique identifier value (e.g. 'S12345', 'https://linkedin.com/in/johndoe'). */
563
+ customKeyValue?: string;
538
564
  /** Enable enhanced dual extraction (structured + free-form). */
539
565
  enhanced?: boolean;
540
566
  /** Tags for property selection. */
@@ -571,6 +597,10 @@ export interface SmartRecallOptions {
571
597
  websiteUrl?: string;
572
598
  /** Entity type filter (e.g. 'Contact', 'Company'). */
573
599
  type?: string;
600
+ /** Custom key name — for entity types with domain-specific unique IDs. */
601
+ customKeyName?: string;
602
+ /** Custom key value — the unique identifier value. */
603
+ customKeyValue?: string;
574
604
  /** Scope results to specific collections by ID. */
575
605
  collectionIds?: string[];
576
606
  /** Scope results to specific collections by name (resolved server-side, case-insensitive). */
@@ -594,6 +624,11 @@ export interface SmartRecallOptions {
594
624
  * In fast_mode, defaults to 0.3 if not specified.
595
625
  */
596
626
  min_score?: number;
627
+ /**
628
+ * Guarantee at least this many results even if they fall below min_score.
629
+ * In fast_mode, defaults to 10. Set to 0 to disable (strict score cutoff).
630
+ */
631
+ min_results?: number;
597
632
  /** Metadata filters for narrowing results. */
598
633
  filters?: Record<string, unknown>;
599
634
  }
@@ -614,6 +649,10 @@ export interface RecallOptions {
614
649
  website_url?: string;
615
650
  /** Website URL (camelCase alias). */
616
651
  websiteUrl?: string;
652
+ /** Custom key name — for entity types with domain-specific unique IDs. */
653
+ customKeyName?: string;
654
+ /** Custom key value — the unique identifier value. */
655
+ customKeyValue?: string;
617
656
  /** Additional filters. */
618
657
  filters?: Record<string, unknown>;
619
658
  }
@@ -628,12 +667,19 @@ export interface BatchMemorizePropertyMapping {
628
667
  extractMemories?: boolean;
629
668
  }
630
669
  export interface BatchMemorizeMapping {
631
- /** Entity type (e.g. 'contact', 'company') */
670
+ /** Entity type (e.g. 'contact', 'company', 'Student', 'Webpage') */
632
671
  entityType: string;
633
672
  /** Source field name that contains the email (e.g. 'email') */
634
673
  email?: string;
635
674
  /** Source field name that contains the website URL (e.g. 'company_website_url') */
636
675
  website?: string;
676
+ /**
677
+ * Custom key name — the identifier name for custom entity types (e.g. 'studentNumber', 'linkedinUrl').
678
+ * Use with `customKey` to specify which source field holds the identifier value.
679
+ */
680
+ customKeyName?: string;
681
+ /** Source field name that contains the custom key value (e.g. 'student_id', 'linkedin_url') */
682
+ customKey?: string;
637
683
  /** Run name for tracking (e.g. 'hubspot Sync (contact) - <uuid>') */
638
684
  runName?: string;
639
685
  /** Property mappings: target property name → mapping config */
@@ -642,6 +688,8 @@ export interface BatchMemorizeMapping {
642
688
  export interface BatchMemorizeOptions {
643
689
  /** Source system label (e.g. 'Hubspot', 'Salesforce') */
644
690
  source: string;
691
+ /** Memorize tier: 'basic' | 'pro' | 'pro_fast' | 'ultra'. Default: 'pro'. */
692
+ tier?: 'basic' | 'pro' | 'pro_fast' | 'ultra';
645
693
  /** Mapping configuration for the sync */
646
694
  mapping: BatchMemorizeMapping;
647
695
  /** Array of source data rows (key-value objects matching sourceField names) */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@personize/sdk",
3
- "version": "0.5.3",
3
+ "version": "0.6.2",
4
4
  "description": "Official Personize SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",