Skip to main content
SONZAI

Priming

Bootstrap agents with user context — display names, demographic facts, chat transcripts from legacy systems, or bulk imports from CSV/CRM.

Priming is how you tell a new agent what it already knows about a user. Instead of waiting for the agent to learn through conversation, you deliver the relevant facts up front: who the user is, where they came from, and what they've said before — all before the first message is exchanged.

What you can build with it

  • Migrations from other LLM frameworks — import chat history from Zep, Mem0, Letta, OpenAI Assistants, LangChain, Character.AI, or any custom transcript store
  • CRM / CSV bulk imports — prime thousands of users in one call with structured contact data
  • Chat-transcript seeding — let the agent "remember" previous conversations from another system
  • Display-name + timezone bootstrap — ensure the agent addresses users correctly from turn 1
  • Onboarding enrichment — load journal entries, support tickets, or prior interactions so the agent sounds familiar on the user's very first chat

Quickstart

Prime a single user with their display name, timezone, and a short narrative block:

import { Sonzai } from "@sonzai-labs/agents";

const client = new Sonzai({ apiKey: process.env.SONZAI_API_KEY! });

const job = await client.agents.priming.primeUser("agent_abc", "user_123", {
display_name: "Mia Tanaka",
metadata: {
  timezone: "Asia/Tokyo",
  company:  "Acme Corp",
  title:    "Platform Lead",
  email:    "[email protected]",
},
content: [
  {
    type: "text",
    body: "Mia joined Acme in 2023 and leads the platform team. She prefers async communication and is an avid coffee enthusiast.",
  },
],
source: "crm_onboarding",
});

console.log(job.job_id, job.status, job.facts_created);

The call returns immediately with a job_id. LLM fact-extraction runs asynchronously in the background — the primed facts appear in memory within seconds.

Core concepts

Metadata vs content

These are two distinct channels for different kinds of information:

  • Metadata is structured and first-class: display_name, company, title, email, phone, timezone, and a custom map for anything else. Sonzai generates facts from metadata fields synchronously — no LLM extraction required — so facts_created is non-zero even with no content blocks.
  • Content is narrative. Content blocks go through the full LLM extraction pipeline and end up as facts in the agent's memory constellation, exactly as if the user had said those things in a conversation.

Content block types

Each PrimeContentBlock has a type and a body:

TypeWhen to use
"text"Narrative facts, bullet-point summaries, freeform notes about the user
"chat_transcript"A prior conversation from another system. Format as User: …\nAgent: … lines, one session per block

The extraction pipeline deduplicates across all blocks — you can safely send both raw transcripts and pre-extracted facts from the same source without producing duplicate memories.

Batch vs single

MethodUse when
primeUserOnboarding a single user, enriching an existing user with new content
batchImportMigrating many users at once from a CSV, CRM, or legacy system

Batch imports return a job ID immediately. Use getImportStatus (or GetImportStatus in Go) to poll until the job's status reaches "complete".

Import jobs

Both primeUser and batchImport are async. The ImportJob response carries:

FieldMeaning
job_idOpaque ID — use it to poll status
status"pending", "processing", "complete", "error"
total_usersNumber of users submitted (batch only)
processed_usersUsers fully extracted so far (batch only)
facts_createdTotal facts written to memory
error_messageSet if the job errored

Batch import

Import multiple users in one call. Useful for migrating from a CRM or seeding a fresh deployment:

const job = await client.agents.priming.batchImport("agent_abc", {
source: "crm_export",
users: [
  {
    user_id:      "user_001",
    display_name: "Mia Tanaka",
    metadata: { email: "[email protected]", timezone: "Asia/Tokyo" },
    content: [
      { type: "text", body: "Mia leads the platform team at Acme Corp." },
    ],
  },
  {
    user_id:      "user_002",
    display_name: "Ren Park",
    metadata: { email: "[email protected]", company: "Beta Labs", title: "CTO" },
    content: [
      { type: "chat_transcript", body: "User: Hey, I need help with our API.\nAgent: Sure, what are you trying to do?" },
    ],
  },
],
});

console.log(`job ${job.job_id}: ${job.total_users} users queued`);

// Poll until done
let status = await client.agents.priming.getImportStatus("agent_abc", job.job_id);
while (status.status !== "complete" && status.status !== "error") {
await new Promise(r => setTimeout(r, 2000));
status = await client.agents.priming.getImportStatus("agent_abc", job.job_id);
}
console.log(`done: ${status.facts_created} facts created`);

Full API

MethodReturnsDescription
primeUser(agentId, userId, opts)PrimeUserResponsePrime or re-prime a single user. Async — returns a job ID.
getPrimeStatus(agentId, userId, jobId)ImportJobCheck status of a single-user priming job.
addContent(agentId, userId, opts)AddContentResponseAppend more content blocks to an already-primed user without overwriting metadata.
getMetadata(agentId, userId)UserPrimingMetadataFetch the stored structured metadata for a user.
updateMetadata(agentId, userId, opts)UpdateMetadataResponsePartially update metadata fields. Provided keys overwrite; omitted keys are preserved.
batchImport(agentId, opts)BatchImportResponseImport many users in one async job.
getImportStatus(agentId, jobId)ImportJobPoll a batch import job by ID.
listImportJobs(agentId, limit?)ImportJobListResponseList recent import jobs for an agent.

Idempotent by design

Calling primeUser more than once for the same user is safe. Content blocks are processed through the same deduplication pipeline as live chat — repeated or overlapping facts are merged, not doubled.

Combines with other features

With Memory — primed facts become durable memory

Content blocks flow through the exact same extraction pipeline as conversational messages. After priming, you can search for primed facts via memory.search:

// After primeUser completes, primed content is searchable
const results = await client.agents.memory.search("agent_abc", {
query: "platform team",
userId: "user_001",
limit: 5,
});

for (const mem of results.results) {
console.log(mem.content, mem.factType, mem.score);
}

Primed facts carry a source_type matching the source string you passed to primeUser or batchImport, so you can distinguish migrated history from organically-learned facts when querying.

With Inventory — structured data import via priming

Use structured_import inside primeUser to seed per-user inventory items alongside narrative facts. This is how you import ownership tables, subscription rosters, or product holdings from a CRM export:

{
  "source": "crm_inventory",
  "structured_import": {
    "entity_type": "product",
    "content_csv": "product_name,quantity,purchase_date\nHiking Backpack,1,2025-09-01\nWater Bottle,2,2025-10-12",
    "column_mapping": {
      "product_name":  { "property": "name", "is_label": true },
      "quantity":      { "property": "quantity", "type": "number" },
      "purchase_date": { "property": "purchased_on" }
    }
  }
}

Each row becomes a fact shaped as "User owns <label>" with the row's columns as metadata. See the CRM / CSV migration guide for a full walkthrough.

With migration guides — concrete from-X paths

The Migrations overview lists per-source recipes with full export + import code for every common origin system. Priming is the underlying mechanism each guide uses — the migration guides show you exactly how to shape your existing data into content blocks.

Tutorials

Next steps

  • Memory — where primed content lands and how it's recalled during conversation
  • Migrations overview — framework-specific recipes for Zep, Mem0, Letta, LangChain, and more
  • Inventory — per-user structured items, often seeded via priming
  • Priming API reference — full endpoint documentation

On this page