npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@personize/sdk

v0.6.6

Published

Official Personize SDK

Downloads

1,250

Readme

Personize SDK

The official Node.js/TypeScript SDK for the Personize Product API. Authenticate with your secret key to access guidelines, smart guidelines, RAG memory, prompt execution, agents, and evaluation tools.

Installation

npm install @personize/sdk

Quick Start

import { Personize } from '@personize/sdk';

const client = new Personize({
    secretKey: 'sk_live_...',
    // baseURL: 'http://localhost:3000' // Optional: for local development
});

// Verify API key
const testResult = await client.test();
console.log(testResult.data.organizationId);

// Read plan limits
const me = await client.me();
console.log(me.data.plan.name);
console.log(me.data.plan.limits);

API Endpoints

| Method | Path | SDK Method | | :--- | :--- | :--- | | Identity | | | | GET | /api/v1/test | client.test() | | GET | /api/v1/me | client.me() | | AI | | | | POST | /api/v1/ai/smart-guidelines | client.ai.smartGuidelines(opts) | | POST | /api/v1/prompt | client.ai.prompt(opts) | | POST | /api/v1/prompt (stream) | client.ai.promptStream(opts) | | Memory | | | | POST | /api/v1/memorize | client.memory.memorize(opts) | | POST | /api/v1/smart-recall | client.memory.smartRecall(opts) | | POST | /api/v1/recall | client.memory.recall(opts) | | POST | /api/v1/search | client.memory.search(opts) | | POST | /api/v1/batch-memorize | client.memory.memorizeBatch(opts) | | POST | /api/v1/smart-memory-digest | client.memory.smartDigest(opts) | | POST | /api/v1/memory/properties | client.memory.properties(opts) | | Guidelines | | | | GET | /api/v1/guidelines | client.guidelines.list() | | POST | /api/v1/guidelines | client.guidelines.create(payload) | | GET | /api/v1/guidelines/:id/structure | client.guidelines.getStructure(id) | | GET | /api/v1/guidelines/:id/section | client.guidelines.getSection(id, opts) | | PATCH | /api/v1/guidelines/:id | client.guidelines.update(id, payload) | | DELETE | /api/v1/guidelines/:id | client.guidelines.delete(id) | | GET | /api/v1/actions/:id/history | client.guidelines.history(id) | | Collections | | | | GET | /api/v1/collections | client.collections.list() | | POST | /api/v1/collections | client.collections.create(payload) | | PATCH | /api/v1/collections/:id | client.collections.update(id, payload) | | DELETE | /api/v1/collections/:id | client.collections.delete(id) | | GET | /api/v1/collections/:id/history | client.collections.history(id) | | Agents | | | | GET | /api/v1/agents | client.agents.list() | | GET | /api/v1/agents/:id | client.agents.get(id) | | POST | /api/v1/agents/:id/run | client.agents.run(id, opts) | | Evaluation | | | | POST | /api/v1/evaluate/memorization-accuracy | client.evaluate.memorizationAccuracy(opts) |

All endpoints require Authorization: Bearer sk_live_... and count against your plan limits.

Usage

Guidelines

// List all guidelines
const vars = await client.guidelines.list();

// Create a guideline
await client.guidelines.create({ name: 'ICP', value: '...', tags: ['sales'] });

// Update a guideline
await client.guidelines.update(guidelineId, { value: 'new content' });

// Get guideline structure (headings)
const structure = await client.guidelines.getStructure(guidelineId);

// Get a specific section
const section = await client.guidelines.getSection(guidelineId, { header: '## Pricing' });

// Delete a guideline
await client.guidelines.delete(guidelineId);

// Version history
const history = await client.guidelines.history(guidelineId, { limit: 5 });

Smart Guidelines

const ctx = await client.ai.smartGuidelines({
    message: 'Write a sales sequence for our top 3 ICPs',
    tags: ['sales'],
    excludeTags: ['internal'],
    sessionId: 'my-session', // for incremental context delivery
});
console.log(ctx.data.compiledContext);

Content Budget

Control how much guideline content is delivered:

const result = await client.ai.smartGuidelines({
  message: "write a cold email",
  maxContentTokens: 5000, // deliver ~2-3 full guidelines, rest as summaries
});

// Demoted guidelines (over budget) returned with id + description for follow-up
if (result.data.budgetMetadata?.demotedGuidelines) {
  for (const g of result.data.budgetMetadata.demotedGuidelines) {
    // Fetch specific section: client.guidelines.getSection(g.id, { header: "Cold Email" })
    console.log(`${g.name}: ${g.description} — sections: ${g.sections.join(', ')}`);
  }
}

Default: 10,000 tokens. Guidelines too large for the budget are automatically trimmed to relevant sections. Remaining guidelines are returned as summaries with id, description, and sections[] for follow-up via client.guidelines.getSection().

Prompt Execution

// Simple prompt (defaults to 'pro' tier)
const response = await client.ai.prompt({
    prompt: 'Summarize our Q4 sales strategy',
});
console.log(response.data?.metadata?.creditsCharged); // credits used

// With explicit tier
const fast = await client.ai.prompt({
    prompt: 'Quick summary of today',
    tier: 'basic',   // cheapest, fastest
});

const premium = await client.ai.prompt({
    prompt: 'Deep analysis of market trends',
    tier: 'ultra',   // highest quality model
});

// BYOK — use your own API key + model + provider (Pro/Enterprise plans only)
const byok = await client.ai.prompt({
    prompt: 'Generate a report',
    openrouterApiKey: 'sk-or-v1-...',  // your OpenRouter key
    model: 'anthropic/claude-sonnet-4-20250514',
    provider: 'openrouter',
});
// BYOK billing: flat 5 credits/call — no per-token charge, you pay your provider directly
// Without BYOK, model/provider are rejected — use tier to control quality level

// Multi-step instructions with evaluation
const result = await client.ai.prompt({
    instructions: [
        { prompt: 'Analyze the data', maxSteps: 5 },
        { prompt: 'Write a summary based on the analysis', maxSteps: 3 },
    ],
    evaluate: { criteria: 'sales', serverSide: true },
});

// Multimodal — image analysis
const analysis = await client.ai.prompt({
    prompt: 'Describe what you see in this screenshot.',
    attachments: [
        { name: 'dashboard.png', mimeType: 'image/png', data: base64EncodedImage },
    ],
});

// Multimodal — PDF extraction via URL
const extraction = await client.ai.prompt({
    prompt: 'Extract the key terms from this contract.',
    attachments: [
        { name: 'contract.pdf', mimeType: 'application/pdf', url: 'https://your-bucket.s3.amazonaws.com/contract.pdf' },
    ],
});

// Output extraction + auto-memorize
const research = await client.ai.prompt({
    instructions: [
        { prompt: 'Research the company using search tools', maxSteps: 5 },
        { prompt: 'Write a personalized outreach email', maxSteps: 3 },
    ],
    outputs: [
        { name: 'company_profile' },
        { name: 'outreach_email' },
    ],
    memorize: {
        email: '[email protected]',
        websiteUrl: 'acme.com',
        type: 'Company',
        captureToolResults: true,
    },
    evaluate: { criteria: 'sales', serverSide: true },
});

console.log(research.data?.outputs?.company_profile);
console.log(research.data?.evaluation?.finalScore);

Streaming Prompt Execution

promptStream() returns an async generator that yields Server-Sent Events as they arrive. Use this for real-time UI updates, progressive output delivery, or when you need structured outputs as soon as each one finishes generating.

import type { PromptSSEEvent } from '@personize/sdk';

// Stream with structured outputs — events arrive as each output closes
for await (const event of client.ai.promptStream({
    prompt: 'Generate a hero section and social proof for our landing page',
    outputs: [
        { name: 'hero' },
        { name: 'social_proof' },
    ],
})) {
    switch (event.type) {
        case 'text':
            // Raw LLM text chunks (everything outside <output> markers)
            process.stdout.write(event.chunk);
            break;

        case 'output':
            // A named output extracted — fired once per output as soon as </output> closes
            // event.data is already parsed (JSON object or plain string)
            console.log(`Output "${event.name}":`, event.data);
            break;

        case 'done':
            // Final event — includes all outputs, evaluation, and metadata
            console.log('All outputs:', event.outputs);
            console.log('Metadata:', event.metadata);
            break;

        case 'error':
            // Non-fatal error during streaming
            console.error('Stream error:', event.message);
            break;
    }
}

SSE Event Types:

| Event | Frequency | Description | | :--- | :--- | :--- | | text | Many per response | Plain text chunks from the LLM | | output | Once per named output | Extracted output (JSON or string) — fired as soon as </output> closes | | step_complete | Once per instruction step | Multi-step mode: step metadata | | done | Once at end | Final reconciliation with all outputs + metadata | | error | 0 or more | Non-fatal streaming errors |

Options:

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | streamTimeout | number | 120000 | Overall stream timeout in ms | | signal | AbortSignal | — | External abort signal for cancellation |

All other PromptOptions parameters (outputs, context, instructions, tier, memorize, evaluate, etc.) are supported.

Cancellation:

const controller = new AbortController();
setTimeout(() => controller.abort(), 5000); // cancel after 5s

for await (const event of client.ai.promptStream({
    prompt: '...',
    signal: controller.signal,
})) {
    // ...
}

Entity Identifiers

All memory endpoints support multiple CRM key types for entity scoping:

| Key | Use case | |-----|----------| | email | Contact lookup | | websiteUrl | Company lookup | | recordId | Direct record ID | | customKeyName + customKeyValue | Custom CRM field (e.g. hubspot_id) | | phoneNumber | Phone-based lookup | | postalCode | Location-based lookup | | deviceId | Device-based lookup | | contentId | Content-based lookup |

You can pass multiple keys simultaneously for better matching.

Memory (RAG)

// Memorize content (dual extraction: structured + free-form)
// Response includes recordId for immediate use in recall/digest calls
const memorized = await client.memory.memorize({
    content: 'Meeting notes: John prefers email contact. He is VP of Sales at Acme Corp.',
    speaker: 'Sales Rep',
    enhanced: true,
    tags: ['meetings'],
    email: '[email protected]',
});
console.log(memorized.data?.recordId); // REC#<hex> — deterministic, use for recall/digest

// Smart recall — deep mode (default): reflection + answer generation, ~10-20s, 2 credits
const results = await client.memory.smartRecall({
    query: 'What does John prefer?',
    limit: 5,
    minScore: 0.7,
    mode: 'deep',
});

// Smart recall — fast mode: skips reflection, ~500ms, 1 credit
const fast = await client.memory.smartRecall({
    query: 'contact info for John',
    email: '[email protected]',
    mode: 'fast',
    // min_results: 10 (default in fast mode — always returns top N even below score threshold)
});

// Custom keys — bring your own identifier for any entity type
// Use customKeyName/customKeyValue when email or websiteUrl don't apply.
// The recordId is generated deterministically from orgId + type + key — same key always resolves to the same record.
await client.memory.memorize({
    content: 'Student enrolled in Advanced AI course. GPA 3.8, Dean\'s List.',
    type: 'Student',
    customKeyName: 'studentNumber',
    customKeyValue: 'S-2024-1234',
    enhanced: true,
});

// More examples: LinkedIn profiles, web pages, code files, products...
await client.memory.memorize({ content: '...', type: 'Person',  customKeyName: 'linkedinUrl',  customKeyValue: 'https://linkedin.com/in/johndoe' });
await client.memory.memorize({ content: '...', type: 'Webpage', customKeyName: 'pageUrl',      customKeyValue: 'https://docs.example.com/api/auth' });
await client.memory.memorize({ content: '...', type: 'File',    customKeyName: 'filePath',     customKeyValue: 'src/auth/oauth.ts' });
await client.memory.memorize({ content: '...', type: 'Product', customKeyName: 'sku',          customKeyValue: 'PRD-X100-BLK' });

// Recall by the same custom key — no need to know the recordId
const student = await client.memory.smartRecall({
    query: 'What courses is this student enrolled in?',
    type: 'Student',
    customKeyName: 'studentNumber',
    customKeyValue: 'S-2024-1234',
    mode: 'fast',
});

// Direct recall — DynamoDB lookup: properties + freeform memories (no AI, type required)
const direct = await client.memory.recall({
    query: 'What do we know about Acme?',
    type: 'Contact',
    email: '[email protected]',
});
// direct.data.memories — structured properties from Snapshot
// direct.data.freeformMemories — AI-extracted memories from Freeform table

// Direct recall by custom key
const student = await client.memory.recall({
    query: 'Academic record',
    type: 'Student',
    customKeyName: 'studentNumber',
    customKeyValue: 'S-2024-1234',
});

// Search/filter records by property conditions — works with any type value
const found = await client.memory.search({
    groups: [{
        conditions: [{ property: 'company-name', operator: 'equals', value: 'Acme Corp' }],
    }],
    returnRecords: true,
    pageSize: 50,
});

// Search across a custom entity type
const deansList = await client.memory.search({
    type: 'Student',
    returnRecords: true,
    groups: [{
        conditions: [{ property: 'gpa', operator: 'GTE', value: 3.5 }],
    }],
});

// Access property values: records[recordId][propertyName].value (plain string)
for (const [recordId, props] of Object.entries(found.data?.records ?? {})) {
    const email = props['email']?.value;           // plain string — whatever was stored
    const company = props['company-name']?.value;
    console.log(`${recordId}: ${email} at ${company}`);
}
// Note: 'email' and 'company-name' must match the property names in your collection definition

// --- Advanced Search Patterns ---

// Key-only lookup: find a record by email without needing property conditions
const byEmail = await client.memory.search({
    email: '[email protected]',
    returnRecords: true,
});

// Key-only lookup: find a record by custom key (no groups needed)
const byStudentNumber = await client.memory.search({
    type: 'Student',
    customKeyName: 'studentNumber',
    customKeyValue: 'S-2024-1234',
    returnRecords: true,
});

// Secondary key: find Students where email is a secondary attribute (not the primary key)
// Works because memorize stores all CRM keys on every LanceDB row
const studentByEmail = await client.memory.search({
    type: 'Student',
    email: '[email protected]',
    returnRecords: true,
});

// Cross-type search: find ALL records with this email across ALL entity types
// Returns Contacts, Students, Employees — whatever has this email
const crossType = await client.memory.search({
    email: '[email protected]',
    returnRecords: true,
});

// Property-value lookup: find records by a stored property (e.g. LinkedIn URL)
// Use this when the lookup key is a property value, not a CRM identifier
const byLinkedIn = await client.memory.search({
    type: 'Contact',
    returnRecords: true,
    groups: [{
        conditions: [{ property: 'linkedin_url', operator: 'EQ', value: 'https://linkedin.com/in/johndoe' }],
    }],
});

// Batch sync — unified call with per-property extractMemories control
// IMPORTANT: Set extractMemories: true on rich text fields (notes, transcripts, descriptions)
// to enable AI extraction and semantic search. Without it, only structured storage occurs.
await client.memory.memorizeBatch({
    source: 'Hubspot',
    mapping: {
        entityType: 'contact',
        // email: 'email' means "use the 'email' field from each row as the contact identifier"
        // The value must match the key name in your rows array (e.g., row.email)
        // Use websiteUrl instead for Company records, or recordId for direct ID matching
        email: 'email',
        properties: {
            email:     { sourceField: 'email',    collectionId: 'col_std', collectionName: 'Standard', extractMemories: false },
            full_name: { sourceField: 'fullname', collectionId: 'col_std', collectionName: 'Standard', extractMemories: false },
            notes:     { sourceField: 'notes',    collectionId: 'col_gen', collectionName: 'Generated', extractMemories: true },
        },
    },
    rows: [
        { email: '[email protected]', fullname: 'John Smith', notes: 'VP Sales, interested in enterprise plan' },
    ],
});

// Batch sync with custom keys — for non-Contact/Company entity types
await client.memory.memorizeBatch({
    source: 'University DB',
    mapping: {
        entityType: 'Student',
        customKeyName: 'studentNumber',   // the identifier name
        customKey: 'student_id',          // source field in rows holding the value
        properties: {
            full_name: { sourceField: 'name',   collectionId: 'col_std', collectionName: 'Standard', extractMemories: false },
            gpa:       { sourceField: 'gpa',    collectionId: 'col_std', collectionName: 'Standard', extractMemories: false },
            notes:     { sourceField: 'notes',  collectionId: 'col_gen', collectionName: 'Generated', extractMemories: true },
        },
    },
    rows: [
        { student_id: 'S-2024-1234', name: 'Alice Chen', gpa: '3.8', notes: 'Dean\'s List, AI research focus' },
        { student_id: 'S-2024-5678', name: 'Bob Park', gpa: '3.5', notes: 'Full-stack internship at Stripe' },
    ],
});

// Smart memory digest — compiled context for an entity
const digest = await client.memory.smartDigest({
    email: '[email protected]',
    type: 'Contact',
    token_budget: 1000,
});
console.log(digest.data?.compiledContext); // ready-to-use markdown for LLM prompts

Get Record Properties

Fetch current property values for a record, joined with collection schema descriptions and the update flag.

// Get specific properties with schema info
const result = await client.memory.properties({
  email: '[email protected]',
  propertyNames: ['Tasks', 'Lifecycle Stage'],
  nonEmpty: true,
});

for (const prop of result.data.properties) {
  console.log(`${prop.name}: ${JSON.stringify(prop.value)}`);
  console.log(`  Type: ${prop.type}, Update: ${prop.update}`);
  console.log(`  Description: ${prop.description}`);
}

Each property includes:

  • value — current value
  • description — from the collection schema, tells AI how to interpret/update
  • updatetrue means replaceable (use memory.update() with propertyValue), false means append-only (use arrayPush)
  • type — property type (text, number, boolean, array, date, options)
  • collectionName — which collection this property belongs to

Options:

  • propertyNames — filter to specific properties (recommended to save tokens)
  • includeDescriptions — join with collection schema (default: true)
  • nonEmpty — exclude null/empty values (default: false)
  • Identifiers: email, websiteUrl, recordId, customKeyName+customKeyValue

Agents

// List agents
const agents = await client.agents.list();

// Get agent details and expected inputs
const agent = await client.agents.get(agentId);
console.log(agent.data.expectedInputs); // ['companyName', 'industry']

// Run an agent
const result = await client.agents.run(agentId, {
    inputs: { companyName: 'Acme Corp', industry: 'SaaS' },
    email: '[email protected]',
});

Collections

// List collections
const collections = await client.collections.list();

// Create a collection
await client.collections.create({
    collectionName: 'Deal Properties',
    entityType: 'Contact',
    properties: [
        { propertyName: 'Deal Stage', type: 'options', options: 'Discovery,Proposal,Closed' },
    ],
});

// Update a collection
await client.collections.update(collectionId, {
    properties: [{ propertyName: 'Budget', type: 'number', description: 'Estimated budget' }],
});

// Delete a collection
await client.collections.delete(collectionId);

// Version history (full snapshots or compact diffs)
const history = await client.collections.history(collectionId, { mode: 'diff', limit: 10 });

Evaluation

// Run memorization accuracy evaluation against a collection
const evaluation = await client.evaluate.memorizationAccuracy({
    collectionId: 'col_123',
    input: 'John Smith is VP of Sales at Acme Corp, based in NYC.',
    skipStorage: true,
});
console.log(evaluation.data.summary.propertiesOptimized);

Tiers & Pricing

Generate Tiers (Prompt)

| Tier | Input Credits/1K tokens | Output Credits/1K tokens | Best For | | :--- | :--- | :--- | :--- | | basic | 1.0 | 2.0 | High-volume, simple tasks | | pro | 1.0 | 3.0 | Balanced quality & cost (default) | | ultra | 1.0 | 5.0 | Complex reasoning, highest quality |

Memorize Tiers

| Tier | Credits/1K tokens | Best For | | :--- | :--- | :--- | | basic | 1 | Bulk imports, simple data | | pro | 3 | General use (default) | | pro_fast | 5 | Pro quality, lower latency | | ultra | 12 | Maximum extraction quality |

Retrieval (Recall & Smart Guidelines)

| Operation | Mode | Credits/Call | | :--- | :--- | :--- | | Smart Recall | mode: 'fast' | 1 | | Smart Recall | mode: 'deep' | 2 | | Smart Guidelines | mode: 'fast' | 1 | | Smart Guidelines | mode: 'deep' | 1 |

Smart Recall cost depends on mode: fast = 1 credit, deep = 2 credits. All other read operations (recall, smart guidelines, smart context) charge a flat 1 credit per call.

1 credit = $0.01.

Direct Providers

BYOK (Bring Your Own Key)

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).

When using BYOK, you must provide both model and provider. Without BYOK, model and provider are rejected — use tier to control quality level.

// BYOK: must specify all three
await client.ai.prompt({
    prompt: '...',
    openrouterApiKey: 'sk-or-v1-...',
    model: 'anthropic/claude-sonnet-4-20250514',
    provider: 'openrouter',
});

// Without BYOK: use tier (model/provider auto-selected)
await client.ai.prompt({
    prompt: '...',
    tier: 'pro',  // basic, pro (default), ultra
});

Error cases:

  • model/provider without openrouterApiKey400 BYOK required
  • openrouterApiKey without model/provider400 model and provider required
  • BYOK on a plan that doesn't allow it → 403 byok_not_allowed

Response metadata includes byok: true and creditsCharged reflecting the flat 5-credit charge.

Smart Recall Modes

The mode parameter controls smart recall behavior:

| Mode | Latency | Credits | Description | | :--- | :--- | :--- | :--- | | "fast" | ~500ms | 1 | Skips reflection and answer generation. Returns raw vector results with guaranteed minimum count. | | "deep" | ~10-20s | 2 | Enables reflection + answer generation for higher-quality, synthesized responses. |

Default is "deep". The mode parameter takes precedence over the individual enable_reflection, generate_answer, and fast_mode flags. If mode is set, those flags are ignored.

Recency Bias

Use prefer_recent to boost recent memories with exponential decay:

const result = await client.memory.smartRecall({
  query: "what changed on this contact recently?",
  email: "[email protected]",
  mode: "deep",
  prefer_recent: true,
  recency_half_life_days: 30, // aggressive: 30-day half-life
});

Default half-life is 90 days. A memory 90 days old scores ~37% of its original relevance. Set to 7-30 for "what happened this week/month" queries.

Best Practices: Query Crafting for smartRecall

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.

Do:

  • Use specific, descriptive queries that match the language of stored data
  • Include entity names, property names, or domain-specific terms
  • Example: "John Smith role title company background" instead of "Tell me about this contact"

Don't:

  • Use vague meta-queries like "What do we know?" or "Tell me everything"
  • Use task-oriented queries like "open tasks pending action items" when only profile data was memorized

Example — AI pipeline pattern:

// BAD: vague query → low similarity scores → few or no results
const bad = await client.memory.smartRecall({ query: 'Tell me about this contact', email });

// GOOD: specific query targeting stored data types
const good = await client.memory.smartRecall({
    query: `${contactName} role company background interests preferences`,
    email,
    mode: 'fast',
});

Guaranteed minimum results: In mode: 'fast', 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.

Configuration

| Option | Type | Required | Description | | :--- | :--- | :--- | :--- | | secretKey | string | Yes | Your secret key (sk_live_...). | | baseURL | string | No | Custom API endpoint (default: https://agent.personize.ai). | | timeout | number | No | Request timeout in ms (default: 30000). | | maxRetries | number | No | Max retry attempts for 429/5xx errors (default: 3). | | retryDelay | number | No | Base delay in ms for exponential backoff (default: 1000). |

Test Key (Local Development)

const client = new Personize({
    secretKey: 'sk_live_TEST_KEY_00000000000000000000000000000000000000000000000000000000',
    baseURL: 'http://localhost:3000',
});

Migration from 0.6.2

New in 0.6.3:

| Feature | Details | | :--- | :--- | | evaluationCriteria on PromptOptions | Compatibility alias for evaluate: { criteria, serverSide: true } | | message on RecallOptions / SmartRecallOptions | Compatibility alias for query | | 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 | | Shorthand semantic memory.search() | search({ query, limit, collectionName }) is accepted and routed to /smart-recall when no filter groups are provided | | collectionName / collectionNames on memorize() | Collection names are resolved client-side into collectionIds | | Legacy collection payload aliases | collections.create() now accepts name, slug, description, array options, and updateSemantics | | records shorthand on memorizeBatch() | Accepts record-style input and normalizes it client-side into memorize() + /batch-memorize calls |

See SDK_0_6_3_COMPATIBILITY_CHANGES.md for the full design notes and tradeoffs.

Migration from 0.5.x

New in 0.6.0:

| Feature | Details | | :--- | :--- | | tier on PromptOptions | Select generate tier: basic, pro (default), ultra | | tier on MemorizeOptions / BatchMemorizeOptions | Select memorize tier: basic, pro, pro_fast, ultra | | openrouterApiKey on PromptOptions | BYOK — use your own API key (Pro/Enterprise plans). Requires model + provider. | | model / provider on PromptOptions | Custom model/provider selection. Requires BYOK (openrouterApiKey). Without BYOK, use tier. | | creditsCharged in response metadata | Credits consumed by the request | | SmartGuidelines mode: 'full'mode: 'deep' | Renamed for consistency. 'full' still accepted for backward compatibility. |

Migration from 0.3.x

Breaking changes in 0.4.0:

| 0.3.x | 0.4.0 | Notes | | :--- | :--- | :--- | | client.memory.recall(opts) | client.memory.smartRecall(opts) | Advanced recall with reflection (route changed to /smart-recall) | | client.memory.export(opts) | client.memory.search(opts) | Filter/search records (route changed to /search) | | MemorizeProOptions | MemorizeOptions | Type renamed (old name still available as deprecated alias) | | RecallProOptions | SmartRecallOptions | Type renamed (old name still available as deprecated alias) | | ExportOptions / ExportResponse | SearchOptions / SearchResponse | Types renamed (old names still available as deprecated aliases) |

New in 0.4.0:

  • client.test() — Verify API key validity
  • client.agents.get(id) — Get agent details and expected inputs
  • client.memory.recall(opts) — Direct DynamoDB lookup: properties + freeform memories (no AI)
  • client.memory.search(opts) — Search/filter records with property-based conditions
  • client.evaluate.memorizationAccuracy(opts) — Three-phase memorization evaluation
  • attachments on PromptOptions — Multimodal support (images, PDFs, documents)
  • sessionId on SmartGuidelinesOptions — Progressive context delivery across multi-step workflows
  • New fields on MemorizeOptions: collectionIds, skipStorage, skipDualWrite, skipPropertySelection
  • New fields on SmartRecallOptions: max_reflection_rounds, filters

Skills

AI-assistant skills for Claude Code, Codex, and Cursor are available separately:

npx skills add personizeai/personize-skills --all

See personizeai/personize-skills for the full catalog.